cv2.imshow () не работает внутри пользовательской функции - PullRequest
3 голосов
/ 15 мая 2019

Функция OpenCV imshow, кажется, работает вне функции, но не внутри этой функции (и я не думаю, что ответ - waitKey ()).Почему это происходит и как я могу это решить?

Я изучаю 2D вейвлеты Габора.Для экспериментов и наблюдений я сначала создал визуализатор ядра.Это хороший, счастливый код JavaScript, который показал мне, какое ядро ​​я создаю.Я был бы очень признателен, если бы вы взглянули на него: http://alpersunter.github.io/Gabor2D/

Это, очевидно, не дает мне того, как выглядит полученное изображение после применения ядра.Поэтому я установил OpenCV (4.1.0) и написал программу на python (3.6.7, установленную в Ubuntu 18.04), которая предположительно должна работать аналогично, но более впечатляюще, как мой визуализатор ядра.Он должен не только вычислять ядро ​​в реальном времени, но также применять фильтр к исходному изображению и его аналогу в оттенках серого и, наконец, отображать их.

Я использую cv2.createTrackbar () для создания ползунков, и после любых изменений параметров трекбар вызывает функцию «myValueChanged (newVal)».Эта функция вычисляет новое ядро ​​с обновленным параметром и, наконец, перерисовывает новое изображение (которое является возвращаемым значением функции cv2.filter2D (src, -1, kernel)).

Теперь все работает, если я вызываюimshow () внутри функции valueChanged ().Однако, если я инкапсулирую вычисления ядра, приложения ядра и cv2.imshow (result) внутри другой функции, которую я назвал «redraw ()», imshow не хочет работать.

Вот пример моего кода:

import cv2
import numpy as np

messi_0_window = "Messi0" # original image
cv2.namedWindow(messi_0_window, cv2.WINDOW_NORMAL)
messi_grey_window = "Messigray" # grayscale of origial
cv2.namedWindow(messi_grey_window, cv2.WINDOW_NORMAL)
messi_1_window = "Messi1" # this will be the result of kernel convolution of rgb messi
cv2.namedWindow(messi_1_window, cv2.WINDOW_NORMAL)
messi_2_window = "Messi2" # and this will be the kernel conv. of grayscale messi
cv2.namedWindow(messi_2_window, cv2.WINDOW_NORMAL)
messi_0 = cv2.imread("messi.jpg")
messi_grey = cv2.cvtColor(messi_0, cv2.COLOR_BGR2GRAY)

kernelSize = (21, 21)
sigma = 10
theta = 0
psi = 0
lambd = 10

def thetaChanged(degrees):
    theta = (degrees/180)*np.pi
    print("I have got a call")
    kernel = cv2.getGaborKernel(kernelSize, sigma, theta, lambd, 1, psi)
    messi_1 = cv2.filter2D(messi_0, -1, kernel)
    messi_2 = cv2.filter2D(messi_grey, -1, kernel)
    cv2.imshow(messi_1_window, messi_1)
    cv2.imshow(messi_2_window, messi_2)

def psiChanged(degrees):
    psi = (degrees/180)*np.pi
    redraw()
    cv2.waitKey(1) # removing this line doesn't help

def redraw():
    print("I have got a call") # This is printed always when I move the slider, independent of whether new image is drawn or not

    kernel = cv2.getGaborKernel(kernelSize, sigma, theta, lambd, 1, psi)
    messi_1 = cv2.filter2D(messi_0, -1, kernel)
    messi_2 = cv2.filter2D(messi_grey, -1, kernel)
    cv2.imshow(messi_1_window, messi_1)
    cv2.imshow(messi_2_window, messi_2)


cv2.createTrackbar("Theta", messi_0_window, 0, 180, thetaChanged)
cv2.createTrackbar("Psi", messi_0_window, 0, 180, psiChanged)

cv2.imshow(messi_0_window, messi_0)
cv2.imshow(messi_grey_window, messi_grey)

cv2.waitKey()
print("Key is now pressed!")

Когда я перемещаю тета-слайдер, на экране появляется новое изображение.Все работает хорошоОднако, если я перемещаю ползунок psi, он рисует только один раз, а затем останавливает рисование нового изображения.Интересно, что если я снова переместлю тета и покажу другое изображение, слайдер psi будет работать только еще один раз и снова остановится.Затем вы перемещаете тэту, и psi снова становится активным, но только для одного изображения.

Я не знаю, как это исправить или это вопрос, связанный с opencv.Может быть, это потому, что мой питон плохой.В любом случае, я надеюсь, что вы научите меня чему-то новому.Все, чему меня научили, действительно ценится.

1 Ответ

2 голосов
/ 16 мая 2019

Ошибка в вашем коде, psi рассматривается как локальная переменная внутри метода psiChanged.Все, что вам нужно сделать, это явно указать, что psi является глобальной переменной в этом методе.Небольшая реструктуризация вашего кода наверняка поможет.Вот последний рабочий скрипт:

import cv2
import numpy as np

messi_0_window = "Messi0" # original image
cv2.namedWindow(messi_0_window, cv2.WINDOW_NORMAL)
messi_grey_window = "Messigray" # grayscale of origial
cv2.namedWindow(messi_grey_window, cv2.WINDOW_NORMAL)
messi_1_window = "Messi1" # this will be the result of kernel convolution of rgb messi
cv2.namedWindow(messi_1_window, cv2.WINDOW_NORMAL)
messi_2_window = "Messi2" # and this will be the kernel conv. of grayscale messi
cv2.namedWindow(messi_2_window, cv2.WINDOW_NORMAL)
messi_0 = cv2.imread("messi.jpg")
messi_grey = cv2.cvtColor(messi_0, cv2.COLOR_BGR2GRAY)

kernelSize = (21, 21)
sigma = 10
theta = 0
psi = 0
lambd = 10

def thetaChanged(degrees):
    global theta
    theta = (degrees/180)*np.pi # Changes the global `theta`
    print("Theta changed - {}".format(theta))
    redraw() # Removed the duplicate code and replaced it with `redraw()` method

def psiChanged(degrees):
    global psi
    psi = (degrees/180)*np.pi # Changes the global `psi`
    print("Psi changed - {}".format(psi))
    redraw()

def redraw():
    global kernelSize, sigma, theta, lambd, psi
    print("I have got a call - {}".format(psi)) # This is printed always when I move the slider, independent of whether new image is drawn or not

    kernel = cv2.getGaborKernel(kernelSize, sigma, theta, lambd, 1, psi)
    messi_1 = cv2.filter2D(messi_0, -1, kernel)
    messi_2 = cv2.filter2D(messi_grey, -1, kernel)
    cv2.imshow(messi_1_window, messi_1)
    cv2.imshow(messi_2_window, messi_2)


cv2.createTrackbar("Theta", messi_0_window, 0, 180, thetaChanged)
cv2.createTrackbar("Psi", messi_0_window, 0, 180, psiChanged)

cv2.imshow(messi_0_window, messi_0)
cv2.imshow(messi_grey_window, messi_grey)

cv2.waitKey()
print("Key is now pressed!")
...