【问题标题】:cv2.imshow() does not work inside a custom functioncv2.imshow() 在自定义函数中不起作用
【发布时间】:2019-05-15 19:12:32
【问题描述】:

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

我正在学习 2D Gabor 小波。为了进行实验和观察,我首先创建了一个内核可视化器。这是一个很好的、快乐的 javascript 代码,它向我展示了我正在创建的内核。如果您看一下,我将不胜感激:http://alpersunter.github.io/Gabor2D/

这显然不能告诉我应用内核后生成的图像是什么样子的。所以我安装了 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 将无法工作。

这是我的代码示例:

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!")

当我移动 theta 滑块时,屏幕上会绘制新图像。一切正常。但是,如果我移动 psi 滑块,它只会绘制一次,然后停止绘制新图像。有趣的是,如果我再次移动 theta 并显示另一张图像,psi 滑块只会再工作一次并再次停止。然后滑动 theta,psi 再次变为活动状态,但只有一张图像。

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

【问题讨论】:

  • 全局变量和局部变量的混合当然没有帮助
  • 如果您希望 thetapsi 和其他代码在您的代码中相同,请将 global thetaglobal psi 等放在所有函数的开头。

标签: python function opencv imshow


【解决方案1】:

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

【讨论】:

  • 考虑为您喜欢回答的问题点赞...它是免费的,它鼓励 OP 和其他有类似问题的人,并为 OP 提供足够的声誉来支持您的答案并接受它。
  • 哦,全局变量!好的,我理解了那部分,但为什么我们不也明确声明为“全局 messi_1_window”?是因为变量范围区分赋值和读取吗?
  • 是的,结果如stackoverflow.com/questions/423379/… 中所述,python 不需要global 来读取全局变量。所以你的编辑在没有global kernelSize ...redraw() 的情况下仍然有效。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-06-23
  • 1970-01-01
  • 2017-04-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多