OpenCV imshow function seems to work outside a function but not inside that function (and I don't think the answer is waitKey()). Why is this happening and how can I solve it?
I am learning 2D Gabor wavelets. For experimenting and observing I first created a kernel visualizer. That is a nice, happy javascript code that showed me what kernel I am creating. I would really appreciate if you take a look on it: http://alpersunter.github.io/Gabor2D/
This obviously does not give me how the resulting image looks like after applying the kernel. So I installed OpenCV (4.1.0) and wrote a program on python (3.6.7 installed on Ubuntu 18.04) that supposedly should act in a similar but more impressive way to my kernel visualizer. It should not only calculate the kernel in real time but also apply the filter to original image and its gray-scale counterpart and lastly show them.
I am using cv2.createTrackbar() to create sliders and after any parameter changes, trackbar calls a "myValueChanged(newVal)" function. That function than calculates new kernel with updated parameter and finally it redraws new image (which is the return value of the function cv2.filter2D(src, -1, kernel)).
Now, everything works if I call imshow() inside the valueChanged() function. However, if I encapsulate kernel calculation, kernel application and cv2.imshow(result) inside another function that I called "redraw()", imshow does not want to work.
Here is a sample of my code:
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!")
When I move the theta slider, new image gets drawn on screen. Everything works well. If, however I move the psi slider, it only draws for once and then stops drawing new image. Interestingly, if I move the theta again and show another image, psi slider works only for one more time and stops again. Then you slide theta, and psi becomes live again but for only one image.
I don't know how to fix this or if this is a question related to opencv. Maybe it is because my python is bad. Anyways I hope you can teach me something new. Anything new taught to me is really appreciated.
theta
,psi
and others to be the same right across your code, putglobal theta
,global psi
etc at the start of all functions. – Mark Setchell