这是一个简单的程序,它使用OpenCV(在Python中)导入图像,将其转换为灰度并在窗口中显示。然后,当用户点击窗口中的位置时,从该点执行泛洪填充。此外,当用户点击该点时,程序应该在该位置打印原始2D像素值。
不幸的是,当向右偏远时,OpenCV会给我一个超出范围的错误,尽管它适用于图像的大部分区域。洪水填充本身在图像中的所有x-y位置都能正常工作。
在工作区域,输出如下所示:
mouse at: 70 , 84
Image Size (220, 186)
cv2: (183.0, 0.0, 0.0, 0.0)
pil im: 255
但是当我走得太远时,输出看起来像这样:
mouse at: 198 , 129
Image Size (220, 186)
OpenCV Error: One of arguments' values is out of range (index is out of range) in cvGet2D
print "cv2: " + str(cv2.cv.Get2D(cv2.cv.fromarray(gray), x, y));
cv2.error: index is out of range
我尝试将图像转换为PIL图像并使用Image.getpixel((x,y))函数,该函数在某种意义上说它没有给出超出范围的异常,但遗憾的是它返回255在所有xy点(事实并非如此)。
我尝试将OpenCV函数调用str(cv2.cv.Get2D(cv2.cv.fromarray(grey),x,y))中xy参数的位置切换为str(cv2.cv.Get2D(cv2。 cv.fromarray(灰色),y,x)),这消除了超出范围的误差,但导致所有位置的虚假返回(255.0,0.0,0.0,0.0)。实际上,该误差的倾斜点,即x维度中的> 186,确实恰好是y维度的长度。这是一个主要线索,但没有解决问题(我的测试图像大小为220 x 186,如上所示)。
import cv2
import cv
import PIL.Image
import numpy
def main():
#mouse event handler flag
CV_EVENT_LBUTTONDOWN = 1;
#THE CODE AT ISSUE IS CONTAINED IN THIS MOUSEHANDLE FUNCTION
def mouseHandle(event, x, y, flag, param):
if (flag == 1):
print "mouse is at: " + str(x) + " , " + str(y);
pilim = Image.fromstring("L", cv.GetSize(cv2.cv.fromarray(gray)),cv2.cv.fromarray(gray).tostring())
print "Image Size " + str(cv.GetSize(cv.fromarray(gray)))
print "cv2: " + str(cv2.cv.Get2D(cv2.cv.fromarray(gray), x, y));
print "pil im: " + str(pilim.getpixel((x,y)))
cv2.floodFill(gray,mask,(x,y), (255,255,0),diff,diff)
cv2.imshow('flood fill',gray)
#THE CODE BELOW IS BASIC OPENCV STUFF TO LOAD THE IMAGE AND INITIATE MOUSECALLS
#reads in the image
im = cv2.imread('image.jpg')
#converts it to grayscale
gray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
cv2.imshow('grayscale', gray)
cv2.waitKey(0);
# flood fill variables
diff = (6,6,6)
mask = zeros((h+2,w+2),uint8)
# show the result in an OpenCV window, calling setMouseCallBack on mouse click
cv2.imshow('flood fill',gray)
cv2.setMouseCallback('flood fill', mouseHandle, CV_EVENT_LBUTTONDOWN)
cv2.waitKey(0)
答案 0 :(得分:2)
我能够解决问题。
首先,关于越界异常。事实证明,cv.Get2D采用y,x形式的像素坐标,这可能令人困惑。使用行cv.Get2D(cv2.cv.fromarray(灰色),y,x));解决了出界问题。
其次,关于虚假像素值。这个真是愚蠢,抱歉伙计们。由于某种原因,CV_EVENT_LBUTTONDOWN标志导致mouseHandle函数执行两次。我以为每次点击都会看到整个输出,但实际上在洪水填充发生后看到了第二个输出,这解释了所有位置的255值。伤心但真实!
起初我怀疑我在某种程度上没有正确使用cv.fromarray,因为cv2.imread('image.jpg')返回类型'numpy.ndarray',而cv.LoadImage('image.jpg')返回类型'cv2.cv.iplimage'。我尝试使用OpenCV1的cv.LoadImage('image.jpg')加载我的图像并使用cv.FloodFill(im2,(x,y),(255,255,0),diff,diff,0,cv.fromarray(mask))用于洪水填充(注意从OpenCV 1到2的参数顺序的变化),并使用cv.Get2D打印xy坐标(cv2.cv.fromarray(灰色),y,x));但问题仍然存在。而且,瞧,答案更简单:)。
当我调试时,我注意到了一些有趣和奇怪的事情。正如我所提到的,我试图用OpenCV 1和OpenCV2填充洪水,但取决于我先调用的洪水填充mouseHandle函数,只执行了一次!
下面是一个输出(点击鼠标后),其顺序为:
cv2.floodFill(gray,mask,(x,y), (255,255,0),diff,diff)
cv.FloodFill(im2, (x,y), (255,255,0), diff, diff, 0, cv.fromarray(mask))
输出:
mouse at: 202 , 13
(220, 186)
cv2: (35.0, 0.0, 0.0, 0.0)
cv1: (35.0, 0.0, 0.0, 0.0)
pil image: 35
mouse at: 202 , 13
(220, 186)
cv2: (255.0, 0.0, 0.0, 0.0)
cv1: (35.0, 0.0, 0.0, 0.0)
pil image: 255
下面是另一个输出(点击鼠标后),顺序为:
cv.FloodFill(im2, (x,y), (255,255,0), diff, diff, 0, cv.fromarray(mask))
cv2.floodFill(gray,mask,(x,y), (255,255,0),diff,diff)
输出:
mouse at: 137 , 126
(220, 186)
cv2: (146.0, 0.0, 0.0, 0.0)
cv1: (146.0, 0.0, 0.0, 0.0)
pil image: 146
mouse at: 137 , 126
(220, 186)
cv2: (146.0, 0.0, 0.0, 0.0)
cv1: (255.0, 0.0, 0.0, 0.0)
pil image: 146
这两行代码的顺序是我做的唯一改变!请注意,pil图像字符串输出遵循cv2 floodfill正在执行的操作,因为它包含相同的数据。