主要思想是先检测外边圆和圆心
然后再外圆内检测小圆,计算小圆圆心与外圆圆心的距离判断是不是有问题
或者可以计算两圆圆心的距离
# coding:utf- | |
import math | |
import cv | |
import numpy as np | |
import os | |
def findNeedlePoints(img): | |
gray_src= cv.cvtColor(img,cv2.COLOR_BGR2GRAY) | |
minThreshValue = | |
_, gray = cv.threshold(gray_src, minThreshValue, 255, cv2.THRESH_BINARY) | |
erosion_size = | |
# element = cv.getStructuringElement(cv2.MORPH_ELLIPSE, (2 * erosion_size + 1, 2 * erosion_size + 1), | |
# (erosion_size, erosion_size)) | |
element = cv.getStructuringElement(cv2.MORPH_ERODE, (2 * erosion_size + 1, 2 * erosion_size + 1), | |
(erosion_size, erosion_size)) | |
# MORPH_ELLIPSE 不同的测试一下 | |
erosion_gray = cv.erode(gray, element, 3) | |
cv.imshow("erosion_gray", erosion_gray) | |
paramsIn = cv.SimpleBlobDetector_Params() | |
paramsIn.filterByArea = True | |
# 不同图片应该调节的参数 | |
paramsIn.minArea = | |
paramsIn.maxArea = | |
paramsIn.minDistBetweenBlobs = | |
paramsIn.filterByColor = True | |
paramsIn.filterByConvexity = False | |
paramsIn.minThreshold =*2 | |
paramsIn.maxThreshold = | |
# 图像取反 | |
needleGray = - erosion_gray.copy() | |
# 中值滤波和腐蚀去噪 | |
needleGray = cv.medianBlur(needleGray, 3) | |
# cv.imshow('needleGray', needleGray) | |
erosion_size = | |
element = cv.getStructuringElement(cv2.MORPH_RECT, (2 * erosion_size + 1, 2 * erosion_size + 1), | |
(erosion_size, erosion_size)) | |
needlePoints = cv.erode(needleGray, element, 1) | |
cv.imshow('needle=Points', needlePoints) | |
detector = cv2.SimpleBlobDetector_create(paramsIn) | |
needleKeypoints = detector.detect(needlePoints) | |
# opencv | |
needle_keypoints = cv.drawKeypoints(needlePoints, needleKeypoints, np.array([]), (255, 0, 0), | |
cv.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS) | |
allNeedlePoints = [] | |
if needleKeypoints is not None: | |
for i in range(len(needleKeypoints)): | |
allNeedlePoints.append(needleKeypoints[i].pt) | |
color_img = cv.cvtColor(needle_keypoints, cv2.COLOR_BGR2RGB) | |
# needle_img = cv.cvtColor(im_with_keypoints, cv2.COLOR_BGR2RGB) | |
cv.imshow('holeShow', color_img) | |
# cv.imshow('needleShow', needle_img) | |
cv.waitKey() | |
def innerHoughCicle(hsv_image, src_image, rect): | |
# 霍夫变换圆检测 | |
gray_src = cv.cvtColor(hsv_image, cv2.COLOR_HSV2RGB) | |
gray_src = cv.cvtColor(gray_src, cv2.COLOR_RGB2GRAY) | |
minThreshValue = | |
_, gray = cv.threshold(gray_src, minThreshValue, 255, cv2.THRESH_BINARY) | |
kernel = np.ones((3, 3), dtype=np.uint8) | |
kernel = np.ones((3, 3), dtype=np.uint8) | |
gray = cv.erode(gray, kernel2, 2) | |
gray = cv.dilate(gray, kernel1, 2) # 1:迭代次数,也就是执行几次膨胀操作 | |
# cv.namedWindow("gray", 2) | |
# cv.imshow("gray", gray) | |
# cv.waitKey() | |
circles = cv.HoughCircles(gray, cv2.HOUGH_GRADIENT, 2, 100, param1=100, param2=60, minRadius=10, maxRadius=100) | |
# 如果没检测到会报错 | |
# 这种判断方式过于简单 | |
if circles is None: | |
print("没有检测到连接器外圆") | |
else: | |
for circle in circles[]: | |
# 圆的基本信息 | |
# print(circle[]) | |
# 坐标行列-圆心坐标 | |
out_x = int(circle[]) | |
out_y = int(circle[]) | |
# 半径 | |
r = int(circle[]) | |
# # 在原图用指定颜色标记出圆的边界 | |
cv.circle(hsv_image, (out_x, out_y), r, (0, 0, 255), 2) | |
# # 画出圆的圆心 | |
cv.circle(hsv_image, (out_x, out_y), 3, (0, 0, 255), -1) | |
cv.namedWindow("hsv_circle", 2) | |
cv.imshow("hsv_circle",hsv_image) | |
cv.waitKey() | |
def outHoughCicle(hsv_image, src_image, rect): | |
# 霍夫变换圆检测 | |
gray_src = cv.cvtColor(hsv_image, cv2.COLOR_HSV2RGB) | |
gray_src = cv.cvtColor(gray_src, cv2.COLOR_RGB2GRAY) | |
minThreshValue = | |
_, gray = cv.threshold(gray_src, minThreshValue, 255, cv2.THRESH_BINARY) | |
kernel = np.ones((3, 3), dtype=np.uint8) | |
kernel = np.ones((3, 3), dtype=np.uint8) | |
gray = cv.erode(gray, kernel2, 2) | |
gray = cv.dilate(gray, kernel1, 2) # 1:迭代次数,也就是执行几次膨胀操作 | |
cv.namedWindow("gray", 2) | |
cv.imshow("gray", gray) | |
cv.waitKey() | |
circles = cv.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1, 10e10, param1=100, param2=60, minRadius=500, maxRadius=10000) | |
# 如果没检测到会报错 | |
# 这种判断方式过于简单 | |
if circles is None: | |
print("没有检测到连接器外圆") | |
else: | |
for circle in circles[]: | |
# 圆的基本信息 | |
# print(circle[]) | |
# 坐标行列-圆心坐标 | |
out_x = int(circle[]) | |
out_y = int(circle[]) | |
# 半径 | |
r = int(circle[]) | |
# # 在原图用指定颜色标记出圆的边界 | |
cv.circle(hsv_image, (out_x, out_y), r, (0, 0, 255), 2) | |
# # 画出圆的圆心 | |
cv.circle(hsv_image, (out_x, out_y), 3, (0, 0, 255), -1) | |
# 画在原图上 | |
cv.circle(src_image, (out_x + rect[0], out_y + rect[1]), r, (0, 0, 255), 2) | |
# # 画出圆的圆心 | |
cv.circle(src_image, (out_x + rect[0], out_y+ rect[1]), 3, (0, 0, 255), -1) | |
cv.namedWindow("hsv_circle", 2) | |
cv.imshow("hsv_circle",hsv_image) | |
cv.namedWindow("src_image", 2) | |
cv.imshow("src_image",src_image) | |
cv.waitKey() | |
# 检测针脚位置 | |
def needelCenter_detect(img): | |
params = cv.SimpleBlobDetector_Params() | |
# Setup SimpleBlobDetector parameters. | |
# print('params') | |
# print(params) | |
# print(type(params)) | |
# Filter by Area. | |
params.filterByArea = True | |
params.minArea = | |
params.maxArea =e3 | |
params.minDistBetweenBlobs = | |
# params.filterByColor = True | |
params.filterByConvexity = False | |
# tweak these as you see fit | |
# Filter by Circularity | |
params.filterByCircularity = False | |
params.minCircularity =.2 | |
# params.blobColor = | |
# # # Filter by Convexity | |
# params.filterByConvexity = True | |
# params.minConvexity =.87 | |
# Filter by Inertia | |
# params.filterByInertia = True | |
# params.filterByInertia = False | |
# params.minInertiaRatio =.01 | |
gray = cv.cvtColor(img, cv2.COLOR_BGR2GRAY) | |
# Detect blobs. | |
minThreshValue = | |
_, gray = cv.threshold(gray, minThreshValue, 255, cv2.THRESH_BINARY) | |
erosion_size = | |
# element = cv.getStructuringElement(cv2.MORPH_ELLIPSE, (2 * erosion_size + 1, 2 * erosion_size + 1), | |
# (erosion_size, erosion_size)) | |
element = cv.getStructuringElement(cv2.MORPH_ERODE, (2 * erosion_size + 1, 2 * erosion_size + 1), | |
(erosion_size, erosion_size)) | |
dilate_gray = cv.dilate(gray, element, 1) | |
# cv.namedWindow("gray", 2) | |
# cv.imshow("gray",dilate_gray) | |
# cv.waitKey() | |
detector = cv.SimpleBlobDetector_create(params) | |
keypoints = detector.detect(dilate_gray) | |
# print(len(keypoints)) | |
# print(keypoints[].pt[0]) | |
# 如果这儿没检测到可能会出错 | |
if len(keypoints) ==: | |
print("没有检测到针角坐标,可能需要调整针角斑点检测参数") | |
print(keypoints) | |
return keypoints | |
else: | |
print("检测到孔的数量", len(keypoints)) | |
# im_with_keypoints = cv.drawKeypoints(img, keypoints, np.array([]), (255, 0, 0), | |
# cv.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS) | |
# | |
# color_img = cv.cvtColor(im_with_keypoints, cv2.COLOR_BGR2RGB) | |
# 画出圆的圆心 | |
# for kp in keypoints: | |
# cv.circle(img, (int(kp.pt[0]), int(kp.pt[1])), 3, (0, 0, 255), -1) | |
# | |
# cv.namedWindow("color_img", 2) | |
# cv.imshow("color_img",img) | |
# # cv.waitKey() | |
return keypoints | |
# 检测外部区域针或孔的位置 | |
def out_circle_detect(rect_hole_info, src): | |
# 灰度化 | |
circle_img = rect_hole_info | |
gray = cv.cvtColor(circle_img, cv2.COLOR_HSV2RGB) | |
gray = cv.cvtColor(gray, cv2.COLOR_RGB2GRAY) | |
# 输出图像大小,方便根据图像大小调节minRadius和maxRadius | |
# print(image.shape) | |
# 进行中值滤波 | |
img = cv.medianBlur(gray, 3) | |
erosion_size = | |
# element = cv.getStructuringElement(cv2.MORPH_ELLIPSE, (2 * erosion_size + 1, 2 * erosion_size + 1), | |
# (erosion_size, erosion_size)) | |
element = cv.getStructuringElement(cv2.MORPH_ERODE, (2 * erosion_size + 1, 2 * erosion_size + 1), | |
(erosion_size, erosion_size)) | |
dilate_gray = cv.dilate(img, element, 1) | |
# cv.namedWindow("dilate_gray", 2) | |
# cv.imshow("dilate_gray", dilate_gray) | |
# cv.waitKey() | |
# 针角圆心坐标 | |
out_x, out_y, r =, 0, 0 | |
# 霍夫变换检测最大圆 | |
circles = cv.HoughCircles(dilate_gray, cv2.HOUGH_GRADIENT, 1, 1000, param1=100, param2=30, minRadius=500, maxRadius=1000) | |
# 如果没检测到会报错 | |
# 这种判断方式过于简单 | |
if circles is None: | |
print("没有检测到连接器外圆") | |
return, 0, 0 | |
else: | |
for circle in circles[]: | |
# 圆的基本信息 | |
# print(circle[]) | |
# 坐标行列-圆心坐标 | |
out_x = int(circle[]) | |
out_y = int(circle[]) | |
# 将检测到的坐标保存 | |
# 半径 | |
r = int(circle[]) | |
# print(r) | |
# # # 在原图用指定颜色标记出圆的边界 | |
cv.circle(circle_img, (out_x, out_y), r, (0, 0, 255), 2) | |
# # 画出圆的圆心 | |
cv.circle(circle_img, (out_x, out_y), 5, (0, 0, 255), -1) | |
cv.namedWindow("circle_imgs", 2) | |
cv.imshow("circle_imgs", circle_img) | |
cv.waitKey() | |
return out_x, out_y, r | |
# 检测内部区域针或孔的位置 | |
def inner_circle_detect(rect_hole_info, src): | |
# 灰度化 | |
circle_img = rect_hole_info | |
gray = cv.cvtColor(circle_img, cv2.COLOR_HSV2RGB) | |
gray = cv.cvtColor(gray, cv2.COLOR_RGB2GRAY) | |
# 输出图像大小,方便根据图像大小调节minRadius和maxRadius | |
# print(image.shape) | |
# 进行中值滤波 | |
img = cv.medianBlur(gray, 3) | |
erosion_size = | |
# element = cv.getStructuringElement(cv2.MORPH_ELLIPSE, (2 * erosion_size + 1, 2 * erosion_size + 1), | |
# (erosion_size, erosion_size)) | |
element = cv.getStructuringElement(cv2.MORPH_ERODE, (2 * erosion_size + 1, 2 * erosion_size + 1), | |
(erosion_size, erosion_size)) | |
dilate_gray = cv.dilate(img, element, 1) | |
# cv.namedWindow("dilate_gray", 2) | |
# cv.imshow("dilate_gray", dilate_gray) | |
# cv.waitKey() | |
# 针角圆心坐标 | |
out_x_p = [] | |
out_y_p = [] | |
rudis = [] | |
# 霍夫变换检测最大圆 | |
circles = cv.HoughCircles(dilate_gray, cv2.HOUGH_GRADIENT, 1, 100, param1=100, param2=30, minRadius=20, maxRadius=100) | |
# 如果没检测到会报错 | |
# 这种判断方式过于简单 | |
if circles is None: | |
print("没有检测到连接器外圆") | |
return out_x_p, out_y_p | |
else: | |
for circle in circles[]: | |
# 圆的基本信息 | |
# print(circle[]) | |
# 坐标行列-圆心坐标 | |
out_x = int(circle[]) | |
out_y = int(circle[]) | |
# 将检测到的坐标保存 | |
out_x_p.append(out_x) | |
out_y_p.append(out_y) | |
# 半径 | |
r = int(circle[]) | |
rudis.append(r) | |
# print(r) | |
# # # 在原图用指定颜色标记出圆的边界 | |
cv.circle(circle_img, (out_x, out_y), r, (0, 0, 255), 2) | |
# # 画出圆的圆心 | |
cv.circle(circle_img, (out_x, out_y), 5, (0, 0, 255), -1) | |
cv.namedWindow("circle_img", 2) | |
cv.imshow("circle_img",circle_img) | |
cv.waitKey() | |
# 记录外圆坐标 | |
out_xpoints = out_x_p.copy() | |
out_ypoints = out_y_p.copy() | |
out_rudis = rudis.copy() | |
# print("out_xpoints",out_xpoints) | |
# print("out_ypoints",out_ypoints) | |
# 只框出单个针角的位置区域 | |
step_center = | |
step_rect = | |
# 遍历所有的孔的位置 | |
# 记录孔的位置 | |
in_x_p = [] | |
in_y_p = [] | |
for i in range(, len(out_xpoints)): | |
out_x_begin = out_xpoints[i] - step_center | |
out_y_begin = out_ypoints[i] - step_center | |
needleRect = circle_img[out_y_begin: out_y_begin + step_rect, out_x_begin: out_x_begin + step_rect] | |
# cv.namedWindow("needleRect", 2) | |
# cv.imshow("needleRect", needleRect) | |
# cv.waitKey() | |
# 根据检测到的圆形连接器中心找针角位置 | |
centerPoint = needelCenter_detect(needleRect) | |
# print(len(centerPoint)) | |
if len(centerPoint) ==: | |
out_x_p.remove(out_xpoints[i]) | |
out_y_p.remove(out_ypoints[i]) | |
rudis.remove(out_rudis[i]) | |
print("调整位置") | |
else: | |
for cp in centerPoint: | |
# 将针角的坐标原还至原图 | |
in_x = int(cp.pt[]) | |
in_y = int(cp.pt[]) | |
in_x += out_x_begin | |
in_y += out_y_begin | |
in_x_p.append(in_x) | |
in_y_p.append(in_y) | |
# # # 画出中心孔的圆心 | |
# cv.circle(circle_img, (in_x, in_y), 4, (0, 255, 0), -1) | |
# # 画出外孔的圆心 | |
# cv.circle(circle_img, (out_xpoints[i], out_ypoints[i]), 4, (0, 0, 255), -1) | |
# # 计算两者的距离 | |
# # 假设通过标定其一个像素代表.0056mm | |
# DPI =.0198 | |
# dis = math.sqrt(math.pow(out_xpoints[i] - in_x,) + math.pow(out_ypoints[i] - in_y,2)) | |
# print("两者相互之间的距离为(mm):", dis*DPI) | |
return in_x_p,in_y_p | |
# cv.namedWindow("image", 2) | |
# cv.imshow("image",circle_img) | |
# cv.waitKey() | |
# if len(out_x_p) ==: | |
# print("没检测到,需要调整位置") | |
# else: | |
# for j in range(,len(out_x_p)): | |
# # 画出外孔的圆心 | |
# cv.circle(circle_img, (out_x_p[j], out_y_p[j]), rudis[j], (0, 0, 255), 3) | |
# cv.circle(circle_img, (out_x_p[j], out_y_p[j]), 3, (0, 0, 255), -1) | |
# | |
# # cv.circle(circle_img, (in_x_p[j], in_y_p[j]), 3, (0, 255, 0), -1) | |
# | |
# cv.namedWindow("image", 2) | |
# cv.imshow("image",circle_img) | |
# cv.waitKey() | |
def j_4_holes_dectWX(imagePath, templatePath): | |
# templatePath需要用户手动框获取ROI | |
img = cv.imread(imagePath) | |
img_roi = cv.imread(templatePath) | |
if img_roi is None: | |
print("no image") | |
# HSV二值化 | |
img_roi = cv.medianBlur(img_roi, 5) # 中值滤波 | |
outx, outy, outR = out_circle_detect(img_roi, img) | |
print(outx, outy, outR ) | |
inx, iny = inner_circle_detect(img_roi, img) | |
if len(inx) == or outx == 0: | |
print("没检测到位置") | |
return "没检测到对象", - | |
else: | |
cv.circle(img_roi, (outx, outy), outR, (0, 0, 255), 3) | |
is_ok = [] | |
for k in range(, len(inx)): | |
# 计算两者的距离 | |
# 假设通过标定其一个像素代表.0056mm | |
# 两者相互之间的距离为(mm):.311053946788194 | |
# 两者相互之间的距离为(mm):.163550379629067 | |
# 两者相互之间的距离为(mm):.95984457900917 | |
# 两者相互之间的距离为(mm):.977940966613671 | |
# 平均值为.103 所以其阈值为9.103 + 0.5 | |
DPI =.0198 | |
dis = math.sqrt(math.pow(outx - inx[k],) + math.pow(outy - iny[k], 2)) | |
dis *= DPI | |
# print("两者相互之间的距离为(mm):", dis) | |
if dis <.603: | |
cv.circle(img_roi, (inx[k], iny[k]), 8, (0, 255, 0), -1) | |
# print("没有插针歪斜,产品合格") | |
is_ok.append() | |
else: | |
cv.circle(img_roi, (inx[k], iny[k]), 20, (0, 0, 255), 3) | |
# print("有插针歪斜,不合格") | |
is_ok.append() | |
# cv.namedWindow("image", 2) | |
# cv.imshow("image",img_roi) | |
# cv.waitKey() | |
isExists = os.path.exists("./runs/J/") | |
if not isExists: | |
os.makedirs("./runs/J/") | |
cv.imwrite("./runs/J599/result.jpg", img_roi) | |
if in is_ok: | |
print("有插针歪斜,不合格") | |
return "有插针歪斜,不合格" | |
else: | |
print("没有插针歪斜,产品合格") | |
return "没有插针歪斜,产品合格" | |
if __name__ == "__main__": | |
reslut = j_4_holes_dectWX("images/Final/E_0_8.jpg","J599-4holes_template.jpg") | |
print(reslut) | |
# | |
# # # #holes | |
# img = cv.imread("images/Final/E_0_8.jpg", 1) | |
# # img_roi = img[:2027, 1713:2751] | |
# # img_roi = img[:2224, 1515:2940] | |
# img_roi = img[:2234, 1480:2950] | |
# cv.imwrite("J599-4holes_template.jpg",img_roi) | |
# | |
# # cv.namedWindow("img_roi",2) | |
# # cv.imshow("img_roi", img_roi) | |
# # cv.waitKey() | |
# if img_roi is None: | |
# print("no image") | |
# else: | |
# # HSV二值化 | |
# img_roi = cv.medianBlur(img_roi, 5) # 中值滤波 | |
# outx, outy, outR = out_circle_detect(img_roi, img) | |
# print(outx, outy, outR ) | |
# inx, iny = inner_circle_detect(img_roi, img) | |
# if len(inx) == or outx == 0: | |
# print("没检测到位置") | |
# else: | |
# cv.circle(img_roi, (outx, outy), outR, (0, 0, 255), 3) | |
# | |
# for k in range(, len(inx)): | |
# # 计算两者的距离 | |
# # 假设通过标定其一个像素代表.0056mm | |
# # 两者相互之间的距离为(mm):.311053946788194 | |
# # 两者相互之间的距离为(mm):.163550379629067 | |
# # 两者相互之间的距离为(mm):.95984457900917 | |
# # 两者相互之间的距离为(mm):.977940966613671 | |
# # 平均值为.103 所以其阈值为9.103 + 0.5 | |
# DPI =.0198 | |
# dis = math.sqrt(math.pow(outx - inx[k],) + math.pow(outy - iny[k], 2)) | |
# dis *= DPI | |
# # print("两者相互之间的距离为(mm):", dis) | |
# if dis >.603: | |
# cv.circle(img_roi, (inx[k], iny[k]), 20, (0, 0, 255), 3) | |
# print("有插针歪斜,不合格") | |
# else: | |
# cv.circle(img_roi, (inx[k], iny[k]), 8, (0, 255, 0), -1) | |
# print("没有插针歪斜,产品合格") | |
# | |
# cv.namedWindow("image", 2) | |
# cv.imshow("image",img_roi) | |
# cv.waitKey() |