我不一定需要源代码,但要查找伪代码或如何处理此问题的想法。我有一个相机指向我的水表,并希望将使用情况记录到数据库中。过去几周我一直在玩OpenCV并且数字检测工作正常。 (最后一个数字会产生问题,因为它会无休止地旋转,而不是像前5个那样与数字对齐,所以整个数字在视野中的时间不到一半。)
无论如何,为了获得最佳分辨率,我想跟踪实际的大红针。现在我走了一圈,找到了最红的"像素,并用它来计算针的角度。只要灯光合适且相机不动,它就可以工作。
我猜测我可以使用Canny边缘检测技巧...最终我只是想找到最长线的角度?并且针是一种独特的颜色应该有助于消除许多误报,但我如何实际应用过滤器?
(请注意,仪表左下方有一个小红色旋转器,与针头颜色相同。我需要确保不会触发某些东西。)
答案 0 :(得分:3)
嗨,今天我对这个问题进行了一些研究,经过多次反复试验,我现在得到了一个很好的解决方案。结果如下。
a
通道中轻松区分红色针(暖色)。 a
通道,阈值并进行形态学操作,因此我们得到二进制掩码。在这些操作之后,它将用于找到潜在的红色针区域。# https://i.stack.imgur.com/5oOGL.jpg
imgname = "stkdata/5oOGL.jpg"
img = cv2.imread(imgname)
## Threshold in grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
retval, threshed = cv2.threshold(gray, 180, 255, cv2.THRESH_BINARY )
## Find wathc region by counting the projector
h,w = img.shape[:2]
x = np.sum(threshed, axis=0)
y = np.sum(threshed, axis=1)
yy = np.nonzero(y>(w/5*255))[0]
xx = np.nonzero(x > (h/5*255))[0]
region = img[yy[0]:yy[-1], xx[0]:xx[-1]]
#cv2.imwrite("region.png", region)
## Change to LAB space
lab = cv2.cvtColor(region, cv2.COLOR_BGR2LAB)
l,a,b = cv2.split(lab)
imglab = np.hstack((l,a,b))
cv2.imwrite("region_lab.png", imglab)
在实验室色彩空间中,可以很容易地区分红色针。
a
通道,阈值,并进行形态学操作。## normalized the a channel to all dynamic range
na = cv2.normalize(a, None, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8UC1)
cv2.imwrite("region_a_normalized.png", na)
## Threshold to binary
retval, threshed = cv2.threshold(na, thresh = 180, maxval=255, type=cv2.THRESH_BINARY)
## Do morphology
kernel = cv2.getStructuringElement( cv2.MORPH_ELLIPSE , (3,3))
opened = cv2.morphologyEx(threshed, cv2.MORPH_OPEN,kernel)
res = np.hstack((threshed, opened))
cv2.imwrite("region_a_binary.png", res)
规范化频道:
阈值并进行形态学操作,我们得到一个二元掩码作为右侧。
## Find contours
contours = cv2.findContours(opened, mode=cv2.RETR_LIST, method=cv2.CHAIN_APPROX_SIMPLE)[-2]
## Draw Contours
res = region.copy()
cv2.drawContours(res, contours, -1, (255,0,0), 1)
cv2.imwrite("region_contours.png", res)
## Filter Contours
for idx, contour in enumerate(contours):
bbox = cv2.boundingRect(contour)
area = bbox[-1]*bbox[-2]
if area < 100:
continue
rot_rect = cv2.minAreaRect(contour)
(cx,cy), (w,h), rot_angle = rot_rect
rbox = np.int0(cv2.boxPoints(rot_rect))
cv2.drawContours(res, [rbox], 0, (0,255,0), 1)
text="#{}: {:2.3f}".format(idx, rot_angle)
org=(int(cx)-10,int(cy)-10)
cv2.putText(res, text=text, org = org, fontFace = 1, fontScale=0.8, color=(0,0,255), thickness = 1, lineType=16)
cv2.imwrite("region_result.png", res)
成立的轮廓:
结果:
我们可以发现,#1
轮廓属于红色针,它的角度是-85.601。
(右方向为0°,逆时针为负,顺时针为正)
此处提供了所有Python代码:
#!/usr/bin/python3
# 2017.10.01 22:59:02 CST
# 2017.10.03 23:49:18 CST
import numpy as np
import cv2
# https://i.stack.imgur.com/5oOGL.jpg
imgname = "stkdata/5oOGL.jpg"
img = cv2.imread(imgname)
## Threshold in grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
retval, threshed = cv2.threshold(gray, 180, 255, cv2.THRESH_BINARY )
## Find wathc region by counting the projector
h,w = img.shape[:2]
x = np.sum(threshed, axis=0)
y = np.sum(threshed, axis=1)
yy = np.nonzero(y>(w/5*255))[0]
xx = np.nonzero(x > (h/5*255))[0]
region = img[yy[0]:yy[-1], xx[0]:xx[-1]]
cv2.imwrite("region.png", region)
## Change to LAB space
lab = cv2.cvtColor(region, cv2.COLOR_BGR2LAB)
l,a,b = cv2.split(lab)
imglab = np.hstack((l,a,b))
cv2.imwrite("region_lab.png", imglab)
## normalized the a channel to all dynamic range
na = cv2.normalize(a, None, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8UC1)
cv2.imwrite("region_a_normalized.png", na)
## Threshold to binary
retval, threshed = cv2.threshold(na, thresh = 180, maxval=255, type=cv2.THRESH_BINARY)
## Do morphology
kernel = cv2.getStructuringElement( cv2.MORPH_ELLIPSE , (3,3))
opened = cv2.morphologyEx(threshed, cv2.MORPH_OPEN,kernel)
res = np.hstack((threshed, opened))
cv2.imwrite("region_a_binary.png", res)
## Find contours
contours = cv2.findContours(opened, mode=cv2.RETR_LIST, method=cv2.CHAIN_APPROX_SIMPLE)[-2]
## Draw Contours
res = region.copy()
cv2.drawContours(res, contours, -1, (255,0,0), 1)
cv2.imwrite("region_contours.png", res)
## Filter Contours
for idx, contour in enumerate(contours):
bbox = cv2.boundingRect(contour)
area = bbox[-1]*bbox[-2]
if area < 100:
continue
rot_rect = cv2.minAreaRect(contour)
(cx,cy), (w,h), rot_angle = rot_rect
rbox = np.int0(cv2.boxPoints(rot_rect))
cv2.drawContours(res, [rbox], 0, (0,255,0), 1)
text="#{}: {:2.3f}".format(idx, rot_angle)
org=(int(cx)-10,int(cy)-10)
#cv2.putText(res, text=text, org = org, fontFace = cv2.FONT_HERSHEY_PLAIN, fontScale=0.7, color=(0,0,255), thickness = 1, lineType=cv2.LINE_AA)
cv2.putText(res, text=text, org = org, fontFace = 1, fontScale=0.8, color=(0,0,255), thickness = 1, lineType=16)
cv2.imwrite("region_result.png", res)
cv2.imshow("result", res); cv2.waitKey();cv2.destroyAllWindows()
我认为首先你可以提取手表区域,然后在区域内搜索红色针,你可以改变色彩空间。这是我在python中的示例代码。
imgname = "5oOGL.jpg"
# https://i.stack.imgur.com/5oOGL.jpg
img = cv2.imread(imgname)
## Threshold in grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
th, imgbin = cv2.threshold(gray, 180, 255, cv2.THRESH_BINARY )
## Find watch region by projecting and counting
h,w = img.shape[:2]
x = np.sum(imgbin, axis=0)
y = np.sum(imgbin, axis=1)
yy = np.nonzero(y>(w/5*255))[0]
xx = np.nonzero(x > (h/5*255))[0]
region = img[yy[0]:yy[-1], xx[0]:xx[-1]]
cv2.imwrite("region.png", region)
cv2.imshow("region", region); cv2.waitKey(0);# cv2.destroyAllWindows()
## Change to LAB space
lab = cv2.cvtColor(region, cv2.COLOR_BGR2LAB)
l,a,b = cv2.split(lab)
imglab = np.hstack((l,a,b))
cv2.imwrite("imglab.png", imglab)
一些链接: