Python imshow()在自定义函数中不起作用

Python imshow()在自定义函数中不起作用,python,function,opencv,imshow,Python,Function,Opencv,Imshow,OpenCV imshow函数似乎在函数外部工作,但不在该函数内部工作(我认为答案不是waitKey()。为什么会发生这种情况?我该如何解决 我正在学习二维Gabor小波。为了进行实验和观察,我首先创建了一个内核可视化工具。这是一个很好的javascript代码,它向我展示了我正在创建的内核。如果您能看一下,我将不胜感激: 这显然没有告诉我应用内核后生成的图像是什么样子的。因此,我安装了OpenCV(4.1.0)并在python上编写了一个程序(3.6.7安装在Ubuntu 18.04上),该程

OpenCV imshow函数似乎在函数外部工作,但不在该函数内部工作(我认为答案不是waitKey()。为什么会发生这种情况?我该如何解决

我正在学习二维Gabor小波。为了进行实验和观察,我首先创建了一个内核可视化工具。这是一个很好的javascript代码,它向我展示了我正在创建的内核。如果您能看一下,我将不胜感激:

这显然没有告诉我应用内核后生成的图像是什么样子的。因此,我安装了OpenCV(4.1.0)并在python上编写了一个程序(3.6.7安装在Ubuntu 18.04上),该程序应该以与我的内核可视化工具类似但更令人印象深刻的方式运行。它不仅要实时计算核函数,而且要对原始图像和灰度图像进行滤波,最后进行显示

我使用cv2.createTrackbar()创建滑块,在任何参数更改后,trackbar调用“myValueChanged(newVal)”函数。该函数然后使用更新的参数计算新内核,最后重新绘制新图像(这是函数cv2.filter2D(src,-1,kernel)的返回值)

现在,如果我在valueChanged()函数中调用imshow(),一切都会正常工作。然而,如果我将内核计算、内核应用程序和cv2.imshow(result)封装在另一个我称为“redraw()”的函数中,imshow就不想工作

以下是我的代码示例:

导入cv2
将numpy作为np导入
梅西0_window=“梅西0”#原始图像
cv2.namedWindow(梅西0窗口,cv2.window正常)
messi_Gray_window=“Messigray”#原始图像的灰度
cv2.namedWindow(梅西灰窗,cv2.window正常)
梅西1_window=“梅西1”#这将是rgb梅西的内核卷积的结果
cv2.namedWindow(梅西窗口,cv2.window窗口,正常)
梅西2_window=“Messi2”#这将是灰度梅西的核心转换
cv2.namedWindow(梅西窗口,cv2.window\u正常)
梅西0=cv2.imread(“mesi.jpg”)
梅西灰=cv2.CVT颜色(梅西灰0,cv2.COLOR\U BGR2GRAY)
内核大小=(21,21)
西格玛=10
θ=0
磅/平方英寸=0
λ=10
def温度变化(度):
θ=(度/180)*np.pi
打印(“我接到一个电话”)
kernel=cv2.getGaborKernel(kernelSize,sigma,theta,lambd,1,psi)
梅西1=cv2.filter2D(梅西0,-1,内核)
梅西2=cv2.filter2D(梅西灰-1,内核)
cv2.imshow(梅西1号窗口,梅西1号)
cv2.imshow(梅西2号窗口,梅西2号)
def PSI已更改(度):
psi=(度/180)*np.pi
重画
cv2.waitKey(1)#删除此行没有帮助
def redraw():
打印(“我接到电话”)#无论是否绘制新图像,当我移动滑块时都会打印此内容
kernel=cv2.getGaborKernel(kernelSize,sigma,theta,lambd,1,psi)
梅西1=cv2.filter2D(梅西0,-1,内核)
梅西2=cv2.filter2D(梅西灰-1,内核)
cv2.imshow(梅西1号窗口,梅西1号)
cv2.imshow(梅西2号窗口,梅西2号)
cv2.createTrackbar(“θ”,梅西0_窗口,0,180,θ变化)
cv2.createTrackbar(“Psi”,messi_0_窗口,0,180,Psi更改)
cv2.imshow(梅西0窗口,梅西0)
cv2.imshow(梅西灰窗,梅西灰)
cv2.waitKey()
打印(“现在按下键!”)
当我移动θ滑块时,屏幕上会绘制新图像。一切正常。但是,如果我移动psi滑块,它只绘制一次,然后停止绘制新图像。有趣的是,如果我再次移动θ并显示另一个图像,psi滑块只工作一次,然后再次停止。然后滑动θ,psi再次激活,但只对一张图像有效


我不知道如何解决这个问题,或者这是否是一个与opencv相关的问题。也许是因为我的python不好。无论如何,我希望你能教我一些新东西。非常感谢您教给我的任何新知识。

您代码中的错误,
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!")

全局和局部变量的混合当然不利于如果你想要代码> theta < /代码>,<代码> PSI < /代码>和其他在你的代码上是相同的,在所有函数的开头放“<代码>全局theta < /代码>,<代码>全局PSI < /代码>等。考虑你喜欢回答的问题。它是免费的,它鼓励OP和其他有类似问题的人,并给予OP足够的声誉,让OP投票支持你的答案并接受它。哦,环球!好的,我理解这一部分,但为什么我们不明确地说“全球梅西窗口”?这是因为变量范围区分赋值和读取吗?是的,正如中所述,python不需要
global
来读取全局变量。因此,您的编辑仍然可以在没有
global kernelSize…
的情况下运行
redraw()