使用 OpenCV 检测数字的小点或小数点
Detect small dot or decimal point of digit using OpenCV
我正在学习 Adrian Rosebrock 关于在 RPi 上识别数字的教程,所以没有 tesseract 或其他任何东西:
https://www.pyimagesearch.com/2017/02/13/recognizing-digits-with-opencv-and-python/
但它不识别小数点,所以我一直在非常努力地创建一个有助于做到这一点的部件。我想我已经接近了,但我不确定我做错了什么。
这是我预处理后的图像
这是尝试识别部分后发生的事情
如您所见,我在某处做错了。已经尝试在 houghCircles
中调整 param1 和 param2
更多示例:
谁能指导我应该做什么?我真的迷路了
============================================= ===================
我正在使用的图像
我正在使用的代码
from imutils.perspective import four_point_transform
from imutils import contours
import imutils
import cv2
import numpy
DIGITS_LOOKUP = {
# Old Library
#(1, 1, 1, 0, 1, 1, 1): 0, # same as new 8
(0, 0, 1, 0, 0, 1, 0): 1,
(1, 0, 1, 1, 1, 1, 0): 2,
(1, 0, 1, 1, 0, 1, 1): 3,
(0, 1, 1, 1, 0, 1, 0): 4,
(1, 1, 0, 1, 0, 1, 1): 5,
#(1, 1, 0, 1, 1, 1, 1): 6,
(1, 0, 1, 0, 0, 1, 0): 7,
(1, 1, 1, 1, 1, 1, 1): 8,
(1, 1, 1, 1, 0, 1, 1): 9,
# New Digital Library
(0, 0, 1, 1, 1, 0, 1): 0,
(1, 0, 1, 0, 0, 1, 1): 2,
(0, 0, 1, 1, 0, 1, 1): 4,
(0, 0, 0, 0, 0, 1, 1): 4,
(1, 1, 0, 0, 0, 1, 1): 5,
(1, 1, 0, 1, 1, 0, 1): 5,
(1, 0, 0, 0, 0, 1, 1): 5,
(1, 1, 1, 0, 0, 0, 0): 7,
(1, 1, 0, 1, 1, 1, 1): 8,
(1, 1, 1, 0, 1, 1, 1): 8
}
image = cv2.imread("10.jpg")
image = imutils.resize(image, height=100)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
edged = cv2.Canny(blurred, 120, 255, 1)
cv2.imshow("1", edged)
cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
cnts = sorted(cnts, key=cv2.contourArea, reverse=True)
displayCnt = None
for c in cnts:
peri = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.02 * peri, True)
if len(approx) == 4:
displayCnt = approx
break
warped = four_point_transform(gray, displayCnt.reshape(4, 2))
output = four_point_transform(image, displayCnt.reshape(4, 2))
thresh = cv2.threshold(warped, 0, 255,
cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
cv2.imshow("2", thresh)
print(thresh.shape)
circles = cv2.HoughCircles(warped, cv2.HOUGH_GRADIENT, 7, 14, param1=0.1, param2=20, minRadius=3, maxRadius=7)
# ensure at least some circles were found
if circles is not None:
circles = numpy.round(circles[0, :]).astype("int")
for (x, y, r) in circles:
cv2.circle(output, (x, y), r, (0, 255, 0), 4)
cv2.rectangle(output, (x - 5, y - 5), (x + 5, y + 5), (0, 128, 255), -1)
# show the output image
cv2.imshow("test", output)
cv2.waitKey(0)
由于小数点可能是正方形而不是圆形,因此使用 cv2.HoughCircles()
可能不是最佳选择。此外,由于您可能有背景噪音,因此尝试查找连接的组件可能会给您误报结果。
下面是使用 cv2.boundingRect()
和 cv2.contourArea()
检测小数的方法。我们可以设置阈值最小和最大区域,这样它只会检测小数点,同时避免检测噪声。
正在尝试检测图片
from imutils.perspective import four_point_transform
from imutils import contours
import imutils
import cv2
import numpy
DIGITS_LOOKUP = {
(1, 1, 1, 0, 1, 1, 1): 0,
(0, 0, 1, 0, 0, 1, 0): 1,
(1, 0, 1, 1, 1, 1, 0): 2,
(1, 0, 1, 1, 0, 1, 1): 3,
(0, 1, 1, 1, 0, 1, 0): 4,
(1, 1, 0, 1, 0, 1, 1): 5,
(1, 1, 0, 1, 1, 1, 1): 6,
(1, 0, 1, 0, 0, 1, 0): 7,
(1, 1, 1, 1, 1, 1, 1): 8,
(1, 1, 1, 1, 0, 1, 1): 9
}
image = cv2.imread("10.jpg")
image = imutils.resize(image, height=100)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
edged = cv2.Canny(blurred, 120, 255, 1)
cv2.imshow("1", edged)
cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
cnts = sorted(cnts, key=cv2.contourArea, reverse=True)
displayCnt = None
for c in cnts:
peri = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.02 * peri, True)
if len(approx) == 4:
displayCnt = approx
break
warped = four_point_transform(gray, displayCnt.reshape(4, 2))
thresh = cv2.threshold(warped, 0, 255,
cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
cv2.imshow("2", thresh)
digit_cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
digit_cnts = imutils.grab_contours(digit_cnts)
threshold_max_area = 25
threshold_min_area = 5
contour_image = thresh.copy()
for c in digit_cnts:
(x,y,w,h) = cv2.boundingRect(c)
area = cv2.contourArea(c)
if area < threshold_max_area and area > threshold_min_area:
cv2.drawContours(contour_image,[c], 0, (100,5,10), 3)
cv2.imshow("detect decimal", contour_image)
cv2.waitKey(0)
研究了一下,参考这个:
得到这些作为结果
但是它们不是很好用,也不是很稳定。如果点突然比以前大了(例如超过 9 个像素,或者图像被调整大小),那么它就不能再使用了,所以这不是一个动态的答案,这是不好的。但是,如果有人感兴趣,我就把它留在这里
代码
#find all your connected components (white blobs in your image)
nb_components, dotput, stats, centroids = cv2.connectedComponentsWithStats(thresh, connectivity=8)
#connectedComponentswithStats yields every seperated component with information on each of them, such as size
#the following part is just taking out the background which is also considered a component, but most of the time we don't want that.
sizes = stats[1:, -1]; nb_components = nb_components - 1
# minimum size of particles we want to keep (number of pixels)
#here, it's a fixed value, but you can set it as you want, eg the mean of the sizes or whatever
min_size = 50
#your answer image
img2 = numpy.zeros((dotput.shape))
#for every component in the image, you keep it only if it's above min_size
#thresh[output == 5 + 1] = 0
dots = []
for i in range(0, nb_components):
if sizes[i] < min_size:
dots.append(centroids[i])
#print(dots)
if dots:
dots.sort(key = lambda x: abs(x[1]-digitCenY))
print(dots)
pDot = -1
for i in range(len(digitCenX)):
if (dots[0][0] <= digitCenX[i]) and (i > 0):
pDot = 0
break
elif (digitCenX[i] <= dots[0][0]) and (i != len(digitCenX)-1):
pDot = 0
break
else:
pDot = 1
cv2.rectangle(output, (int(dots[pDot][0]), int(dots[pDot][1])), (int(dots[pDot][0]) + 3, int(dots[pDot][1]) + 3), (0, 255, 0), 1)
我正在学习 Adrian Rosebrock 关于在 RPi 上识别数字的教程,所以没有 tesseract 或其他任何东西: https://www.pyimagesearch.com/2017/02/13/recognizing-digits-with-opencv-and-python/
但它不识别小数点,所以我一直在非常努力地创建一个有助于做到这一点的部件。我想我已经接近了,但我不确定我做错了什么。
这是我预处理后的图像
这是尝试识别部分后发生的事情
如您所见,我在某处做错了。已经尝试在 houghCircles
中调整 param1 和 param2更多示例:
谁能指导我应该做什么?我真的迷路了
============================================= ===================
我正在使用的图像
我正在使用的代码
from imutils.perspective import four_point_transform
from imutils import contours
import imutils
import cv2
import numpy
DIGITS_LOOKUP = {
# Old Library
#(1, 1, 1, 0, 1, 1, 1): 0, # same as new 8
(0, 0, 1, 0, 0, 1, 0): 1,
(1, 0, 1, 1, 1, 1, 0): 2,
(1, 0, 1, 1, 0, 1, 1): 3,
(0, 1, 1, 1, 0, 1, 0): 4,
(1, 1, 0, 1, 0, 1, 1): 5,
#(1, 1, 0, 1, 1, 1, 1): 6,
(1, 0, 1, 0, 0, 1, 0): 7,
(1, 1, 1, 1, 1, 1, 1): 8,
(1, 1, 1, 1, 0, 1, 1): 9,
# New Digital Library
(0, 0, 1, 1, 1, 0, 1): 0,
(1, 0, 1, 0, 0, 1, 1): 2,
(0, 0, 1, 1, 0, 1, 1): 4,
(0, 0, 0, 0, 0, 1, 1): 4,
(1, 1, 0, 0, 0, 1, 1): 5,
(1, 1, 0, 1, 1, 0, 1): 5,
(1, 0, 0, 0, 0, 1, 1): 5,
(1, 1, 1, 0, 0, 0, 0): 7,
(1, 1, 0, 1, 1, 1, 1): 8,
(1, 1, 1, 0, 1, 1, 1): 8
}
image = cv2.imread("10.jpg")
image = imutils.resize(image, height=100)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
edged = cv2.Canny(blurred, 120, 255, 1)
cv2.imshow("1", edged)
cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
cnts = sorted(cnts, key=cv2.contourArea, reverse=True)
displayCnt = None
for c in cnts:
peri = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.02 * peri, True)
if len(approx) == 4:
displayCnt = approx
break
warped = four_point_transform(gray, displayCnt.reshape(4, 2))
output = four_point_transform(image, displayCnt.reshape(4, 2))
thresh = cv2.threshold(warped, 0, 255,
cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
cv2.imshow("2", thresh)
print(thresh.shape)
circles = cv2.HoughCircles(warped, cv2.HOUGH_GRADIENT, 7, 14, param1=0.1, param2=20, minRadius=3, maxRadius=7)
# ensure at least some circles were found
if circles is not None:
circles = numpy.round(circles[0, :]).astype("int")
for (x, y, r) in circles:
cv2.circle(output, (x, y), r, (0, 255, 0), 4)
cv2.rectangle(output, (x - 5, y - 5), (x + 5, y + 5), (0, 128, 255), -1)
# show the output image
cv2.imshow("test", output)
cv2.waitKey(0)
由于小数点可能是正方形而不是圆形,因此使用 cv2.HoughCircles()
可能不是最佳选择。此外,由于您可能有背景噪音,因此尝试查找连接的组件可能会给您误报结果。
下面是使用 cv2.boundingRect()
和 cv2.contourArea()
检测小数的方法。我们可以设置阈值最小和最大区域,这样它只会检测小数点,同时避免检测噪声。
正在尝试检测图片
from imutils.perspective import four_point_transform
from imutils import contours
import imutils
import cv2
import numpy
DIGITS_LOOKUP = {
(1, 1, 1, 0, 1, 1, 1): 0,
(0, 0, 1, 0, 0, 1, 0): 1,
(1, 0, 1, 1, 1, 1, 0): 2,
(1, 0, 1, 1, 0, 1, 1): 3,
(0, 1, 1, 1, 0, 1, 0): 4,
(1, 1, 0, 1, 0, 1, 1): 5,
(1, 1, 0, 1, 1, 1, 1): 6,
(1, 0, 1, 0, 0, 1, 0): 7,
(1, 1, 1, 1, 1, 1, 1): 8,
(1, 1, 1, 1, 0, 1, 1): 9
}
image = cv2.imread("10.jpg")
image = imutils.resize(image, height=100)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
edged = cv2.Canny(blurred, 120, 255, 1)
cv2.imshow("1", edged)
cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
cnts = sorted(cnts, key=cv2.contourArea, reverse=True)
displayCnt = None
for c in cnts:
peri = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.02 * peri, True)
if len(approx) == 4:
displayCnt = approx
break
warped = four_point_transform(gray, displayCnt.reshape(4, 2))
thresh = cv2.threshold(warped, 0, 255,
cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
cv2.imshow("2", thresh)
digit_cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
digit_cnts = imutils.grab_contours(digit_cnts)
threshold_max_area = 25
threshold_min_area = 5
contour_image = thresh.copy()
for c in digit_cnts:
(x,y,w,h) = cv2.boundingRect(c)
area = cv2.contourArea(c)
if area < threshold_max_area and area > threshold_min_area:
cv2.drawContours(contour_image,[c], 0, (100,5,10), 3)
cv2.imshow("detect decimal", contour_image)
cv2.waitKey(0)
研究了一下,参考这个:
得到这些作为结果
但是它们不是很好用,也不是很稳定。如果点突然比以前大了(例如超过 9 个像素,或者图像被调整大小),那么它就不能再使用了,所以这不是一个动态的答案,这是不好的。但是,如果有人感兴趣,我就把它留在这里
代码
#find all your connected components (white blobs in your image)
nb_components, dotput, stats, centroids = cv2.connectedComponentsWithStats(thresh, connectivity=8)
#connectedComponentswithStats yields every seperated component with information on each of them, such as size
#the following part is just taking out the background which is also considered a component, but most of the time we don't want that.
sizes = stats[1:, -1]; nb_components = nb_components - 1
# minimum size of particles we want to keep (number of pixels)
#here, it's a fixed value, but you can set it as you want, eg the mean of the sizes or whatever
min_size = 50
#your answer image
img2 = numpy.zeros((dotput.shape))
#for every component in the image, you keep it only if it's above min_size
#thresh[output == 5 + 1] = 0
dots = []
for i in range(0, nb_components):
if sizes[i] < min_size:
dots.append(centroids[i])
#print(dots)
if dots:
dots.sort(key = lambda x: abs(x[1]-digitCenY))
print(dots)
pDot = -1
for i in range(len(digitCenX)):
if (dots[0][0] <= digitCenX[i]) and (i > 0):
pDot = 0
break
elif (digitCenX[i] <= dots[0][0]) and (i != len(digitCenX)-1):
pDot = 0
break
else:
pDot = 1
cv2.rectangle(output, (int(dots[pDot][0]), int(dots[pDot][1])), (int(dots[pDot][0]) + 3, int(dots[pDot][1]) + 3), (0, 255, 0), 1)