用随机采样一致性处理后拟合直线效果会更好
# coding:utf-8
import math
import cv2
import numpy as np
import xml.etree.ElementTree as ET
import random
import matplotlib.pyplot as plt
from PIL import ImageFont, Image, ImageDraw
# from utils.plots import Annotator, colors, save_one_box
from labelutils.plots import Annotator, colors
global DPI
DPI = 0.00245
def fit_line_by_ransac(point_list, sigma=1, iters=1000, P=0.99):
# 使用RANSAC算法拟合直线
# 迭代最大次数 iters = 1000
# 数据和模型之间可接受的差值 sigma
# 希望的得到正确模型的概率P = 0.99
# 最好模型的参数估计
best_a = 0 # 直线斜率
best_b = 0 # 直线截距
n_total = 0 # 内点数目
for i in range(iters):
# 随机选两个点去求解模型
sample_index = random.sample(range(len(point_list)), 2)
x_1 = point_list[sample_index[0]][0]
y_1 = point_list[sample_index[0]][1]
x_2 = point_list[sample_index[1]][0]
y_2 = point_list[sample_index[1]][1]
if x_2 == x_1:
continue
# y = ax + b 求解出a,b
a = (y_2 - y_1) / (x_2 - x_1)
b = y_1 - a * x_1
# 算出内点数目
total_inlier = 0
for index in range(len(point_list)):
y_estimate = a * point_list[index][0] + b
if abs(y_estimate - point_list[index][1]) < sigma:
total_inlier += 1
# 判断当前的模型是否比之前估算的模型好
if total_inlier > n_total:
iters = math.log(1 - P) / math.log(1 - pow(total_inlier / len(point_list), 2))
n_total = total_inlier
best_a = a
best_b = b
# 判断是否当前模型已经符合超过一半的点
if total_inlier > len(point_list) // 2:
break
return best_a, best_b
def get_distance_point2line(point, line_ab): # 求点到直线的距离
"""
Args:
point: [x0, y0]
line_ab: [k, b]
"""
k, b = line_ab
distance = abs(k * point[0] - point[1] + b) / math.sqrt(k ** 2 + 1)
return distance
def drawLines(img0, allCirclesCenter, wxdis_thres, DPI):
img = img0.copy()
# 所有点按照x轴排序
def takeFirst(elem):
return elem[0]
allCirclesCenter.sort(key=takeFirst) #
# 计算两排点的中心线
nptest = np.array(allCirclesCenter)
line = cv2.fitLine(nptest, cv2.DIST_L2, 0, 0.001, 0.0)
k = line[1] / line[0]
b = line[3] - k * line[2]
# 区分上下各点
line1_yx, line2_yx = [], []
if -10e5 < k < 10e5: # 如果是水平线,可以正常判断出上下点
print('中间线line0: \ny = {:0.8f}x + {:0.8f}'.format(k[0], b[0]))
# ptStart, ptEnd = (0, int(k * 0 + b)), (img.shape[1], int(k * img.shape[1] + b))
ptStart, ptEnd = (int(allCirclesCenter[0][0]), int(k * allCirclesCenter[0][0] + b)), (int(allCirclesCenter[-1][0]), int(k * allCirclesCenter[-1][0] + b))
cv2.line(img, ptStart, ptEnd, (0, 0, 255), thickness=2, lineType=3) # 画线
# cv2.imwrite('./test/lin0_gray.png', img)
# 区分上下各点,拟合两条直线
for i in allCirclesCenter:
if i[1] < float(k * i[0] + b):
line1_yx.append(i)
else:
line2_yx.append(i)
else: # 对于斜率过大的直线,寻找x坐标相距最远的两个点,得到中心线,根据x坐标区分各点(其实也不影响拟合直线,只不过需要根据x轴做判断)
print('中间线line0: \ny = {:0.8f}x + {:0.8f}'.format(k[0], b[0]))
ptStart, ptEnd = (int((0-b)/k), 0), (int((img.shape[0]-b)/k), img.shape[0]) # 根据y值画线
cv2.line(img, ptStart, ptEnd, (0, 0, 255), thickness=2, lineType=3)
minx_point, maxx_point = allCirclesCenter[0], allCirclesCenter[0]
for po1 in allCirclesCenter:
if po1[0] < minx_point[0]:
minx_point = po1
if po1[0] > maxx_point[0]:
maxx_point = po1
line0_x = (maxx_point[0] - minx_point[0])/2 + minx_point[0]
for i in allCirclesCenter:
if i[0] < line0_x:
line1_yx.append(i)
else:
line2_yx.append(i)
is_defect = 0
annotator1 = Annotator(img, line_width=4, example='distance: ') # 初始化生成框函数
# line1 求第一条直线###################
nptest1 = np.array(line1_yx)
print("nptest1", nptest1)
line1 = cv2.fitLine(nptest1, cv2.DIST_L2, 0, 0.01, 0.0)
k1 = line1[1] / line1[0]
b1 = line1[3] - k1 * line1[2]
print('第1排line1: \ny = {:0.8f}x + {:0.8f}'.format(k1[0], b1[0]))
ran_k, ran_b = fit_line_by_ransac(nptest1)
print('line1: y=%s*x+%s' %(ran_k, ran_b))
if -10e5 < k < 10e5: # 若斜率不大
def takeFirst(elem):
return elem[0]
line1_yx.sort(key=takeFirst)
# pd_1 = (abs(line1_yx[-1][0] - line1_yx[0][0]) / (len(line1_yx) - 1))
# pd_2 = 0
# for pd_i in range(len(line1_yx)):
# if pd_i < len(line1_yx) - 2:
# pd_2 += ((line1_yx[pd_i + 1][0] - line1_yx[pd_i][0]) / (len(line1_yx) - 1))
# pd_3 = (pd_1 + pd_2) / 2 # 判断针孔沿直线方向歪斜的判断标准
pd_1, pd_2 = 0, 0
dis_pdi = []
for pd_i in range(len(line1_yx)):
if pd_i < len(line1_yx) - 2:
dis_pdi.append(math.sqrt(pow(line1_yx[pd_i + 1][1] - line1_yx[pd_i][1], 2) + pow(line1_yx[pd_i + 1][0] - line1_yx[pd_i][0], 2)))
# pd_2 += ((line1_yx[pd_i + 1][0] - line1_yx[pd_i][0]) / (len(line1_yx) - 1))
for dis_i in dis_pdi:
pd_1 += (dis_i / len(dis_pdi)) # 平均值
ptStart, ptEnd = (int(line1_yx[0][0]), int(k1 * line1_yx[0][0] + b1)), (int(line1_yx[-1][0]), int(k1 * line1_yx[-1][0] + b1))
cv2.line(img, ptStart, ptEnd, (255, 0, 0), 2)
# 绘制随机采样一致拟合的线
rans_pt_Start, rans_pt_End = (int(line1_yx[0][0]), int(ran_k * line1_yx[0][0] + ran_b)), (int(line1_yx[-1][0]), int(ran_k * line1_yx[-1][0] + ran_b))
cv2.line(img, rans_pt_Start, rans_pt_End, (0, 255, 0), 2)
# 计算各点到对应直线的距离,如果从超过最大距离判断为缺陷(********需要使用标定板,计算图片对应的实际距离)
for i in line1_yx: # 可以显示存在缺陷的点的位置
# distance = abs(k1 * i[0] - i[1] + b1) / math.sqrt(k1 ** 2 + 1)
#
# # 在原图绘制点的偏差值
# # cv2.putText(img, str(distance[0]), (int(i[0] + 5), int(i[1] + 5)), 0, 2, (0, 255, 0), thickness=3)
# # a = int(distance[0])
# if round((distance[0] * DPI), 2) >= 0.05:
# annotator1.box_label([int(i[0]), int(i[1]), int(i[0] + 10), int(i[1] + 10)], f'{round((distance[0] * DPI), 2)}', color=(0, 255, 0))
# 随机采样一致算法拟合后线与孔的距离
distance = abs(ran_k * i[0] - i[1] + ran_b) / math.sqrt(ran_k ** 2 + 1)
# 在原图绘制点的偏差值
# cv2.putText(img, str(distance[0]), (int(i[0] + 5), int(i[1] + 5)), 0, 2, (0, 255, 0), thickness=3)
# a = int(distance[0])
if round((distance * DPI), 2) >= 0.05:
annotator1.box_label([int(i[0]), int(i[1]), int(i[0] + 10), int(i[1] + 10)],
f'{round((distance * DPI), 2)}', color=(0, 255, 0))
# cv2.namedWindow("img", 2) # 显示大分辨率图片
# cv2.imshow('img', img)
# cv2.waitKey()
# cv2.imwrite('./txt.png', img)
if (distance * DPI) > wxdis_thres: # 判断不合格的距离,具体范围需要调整***********
print("第1排点存在不合格: ({},{})".format(str(i[0]), str(i[1])))
cv2.circle(img, (int(i[0]), int(i[1])), 4, (0, 0, 255), 2) # 显示有缺陷的针孔
cv2.rectangle(img, (int(i[0]-25), int(i[1])-25), (int(i[0] + 25), int(i[1] + 25)), (0, 0, 255), 2)
is_defect = 1
# 暂时不用测试这个 判断针孔沿直线方向歪斜
# for i in range(1, len(line1_yx)):
# if ((abs(line1_yx[i][0]-line1_yx[i-1][0])-pd_1) * DPI) >= wxdis_thres:
# print("第1排点直线方向存在不合格: ({},{})".format(str(line1_yx[i][0]), str(line1_yx[i][1])))
# cv2.rectangle(img, (int(line1_yx[i][0] - 25), int(line1_yx[i][1] - 25)), (int(line1_yx[i][0] + 25), int(line1_yx[i][1] + 25)), (0, 0, 255), 2)
# is_defect = 1
else:
print(10*"hello")
def takeSecond(elem):
return elem[1]
line1_yx.sort(key=takeSecond)
# pd_1 = (abs(line1_yx[-1][1] - line1_yx[0][1]) / (len(line1_yx) - 1))
# pd_2 = 0
# for pd_i in range(len(line1_yx)):
# if pd_i < len(line1_yx) - 2:
# pd_2 += ((line1_yx[pd_i + 1][1] - line1_yx[pd_i][1]) / (len(line1_yx) - 1))
# pd_3 = (pd_1 + pd_2) / 2 # 判断针孔沿直线方向歪斜的判断标准
pd_1, pd_2 = 0, 0
dis_pdi = []
for pd_i in range(len(line1_yx)):
if pd_i < len(line1_yx) - 2:
dis_pdi.append(math.sqrt(pow(line1_yx[pd_i + 1][1] - line1_yx[pd_i][1], 2) + pow(line1_yx[pd_i + 1][0] - line1_yx[pd_i][0], 2)))
# pd_2 += ((line1_yx[pd_i + 1][0] - line1_yx[pd_i][0]) / (len(line1_yx) - 1))
for dis_i in dis_pdi:
pd_1 += (dis_i / len(dis_pdi)) # 平均值
ptStart, ptEnd = (int((0-b1)/k1), 0), (int((img.shape[0]-b1)/k1), img.shape[0])
cv2.line(img, ptStart, ptEnd, (255, 0, 0), 2)
for i in line1_yx: # 可以显示存在缺陷的点的位置
distance = abs(i[0] - int((i[1]-b1)/k1))
# 在原图绘制点的偏差值
# cv2.putText(img, str(distance[0]), (int(i[0] + 5), int(i[1] + 5)), 0, 2, (0, 255, 0), thickness=3)
if round((distance[0] * DPI), 2) >= 0.05:
annotator1.box_label([int(i[0]), int(i[1]), int(i[0] + 10), int(i[1] + 10)], f'{round((distance[0] * DPI), 2)}', color=(0, 255, 0))
if (distance * DPI) > wxdis_thres: # 判断不合格的距离,具体范围需要调整***********
print("第1排点存在不合格: ({},{})".format(str(i[0]), str(i[1])))
cv2.circle(img, (int(i[0]), int(i[1])), 4, (0, 0, 255), 2) # 显示有缺陷的针孔
cv2.rectangle(img, (int(i[0] - 25), int(i[1]) - 25), (int(i[0] + 25), int(i[1] + 25)), (0, 0, 255), 2)
is_defect = 1
# 判断针孔沿直线方向歪斜
for i in range(1, len(line1_yx)):
if ((abs(line1_yx[i][1]-line1_yx[i-1][1])-pd_1) * DPI) >= wxdis_thres:
print("第1排点直线方向存在不合格: ({},{})".format(str(line1_yx[i][0]), str(line1_yx[i][1])))
cv2.rectangle(img, (int(line1_yx[i][0] - 25), int(line1_yx[i][1] - 25)), (int(line1_yx[i][0] + 25), int(line1_yx[i][1] + 25)), (0, 0, 255), 2)
is_defect = 1
cv2.namedWindow("imgline1", 2) # 显示大分辨率图片
cv2.imshow('imgline1', img)
cv2.waitKey()
cv2.imwrite('./test/lin1.png', img)
# lin2 求第二条直线#########################
nptest2 = np.array(line2_yx)
print("nptest2", nptest2)
line2 = cv2.fitLine(nptest2, cv2.DIST_L2, 0, 0.01, 0.0)
k2 = line2[1] / line2[0]
b2 = line2[3] - k2 * line2[2]
print('第2排line2: \ny = {:0.8f}x + {:0.8f}'.format(k2[0], b2[0]))
ran_k2, ran_b2 = fit_line_by_ransac(nptest2)
print('line2: y=%s*x+%s' %(ran_k2, ran_b2))
if -10e5 < k < 10e5: # 若斜率不大
def takeFirst(elem):
return elem[0]
line2_yx.sort(key=takeFirst)
# pd_1 = (abs(line2_yx[-1][0] - line2_yx[0][0]) / (len(line2_yx) - 1))
# pd_2 = 0
# for pd_i in range(len(line2_yx)):
# if pd_i < len(line2_yx) - 2:
# pd_2 += ((line2_yx[pd_i + 1][0] - line2_yx[pd_i][0]) / (len(line2_yx) - 1))
# pd_3 = (pd_1 + pd_2) / 2 # 判断针孔沿直线方向歪斜的判断标准
pd_1, pd_2 = 0, 0
# dis_pdi = []
# for pd_i in range(len(line2_yx)):
# if pd_i < len(line2_yx) - 2:
# dis_pdi.append(math.sqrt(pow(line2_yx[pd_i + 1][1] - line2_yx[pd_i][1], 2) + pow(line2_yx[pd_i + 1][0] - line2_yx[pd_i][0], 2)))
# for dis_i in dis_pdi:
# pd_1 += (dis_i / len(dis_pdi)) # 平均值
ptStart, ptEnd = (int(line2_yx[0][0]), int(k2 * line2_yx[0][0] + b2)), (int(line2_yx[-1][0]), int(k2 * line2_yx[-1][0] + b2))
cv2.line(img, ptStart, ptEnd, (255, 0, 0), 2) # 像素值必须是整数****************
# 绘制随机采样一致拟合的直线
ptStart, ptEnd = (int(line2_yx[0][0]), int(ran_k2 * line2_yx[0][0] + ran_b2)), (
int(line2_yx[-1][0]), int(ran_k2 * line2_yx[-1][0] + ran_b2))
cv2.line(img, ptStart, ptEnd, (0, 255, 0), 2) # 像素值必须是整数****************
# 计算各点到对应直线的距离,如果从超过最大距离判断为缺陷(********需要使用标定板,计算图片对应的实际距离)
for j in line2_yx:
# distance = abs(k2 * j[0] - j[1] + b2) / math.sqrt(k2 ** 2 + 1)
# if round((distance[0] * DPI), 2) >= 0.05:
# annotator1.box_label([int(j[0]), int(j[1]), int(j[0] + 10), int(j[1] + 10)],
# f'{round((distance[0] * DPI), 2)}', color=(0, 255, 0))
# 用随机采样一致拟合的直线距离
distance = abs(ran_k2 * j[0] - j[1] + ran_b2) / math.sqrt(ran_k2 ** 2 + 1)
# 在原图绘制点的偏差值
# cv2.putText(img, str(distance[0]), (int(j[0] + 5), int(j[1] + 5)), 0, 2, (0, 255, 0), thickness=3)
if round((distance * DPI), 2) >= 0.05:
annotator1.box_label([int(j[0]), int(j[1]), int(j[0] + 10), int(j[1] + 10)], f'{round((distance * DPI), 2)}', color=(0, 255, 0))
if (distance * DPI) > wxdis_thres:
print("第2排点存在不合格: ({},{})".format(str(j[0]), str(j[1])))
cv2.circle(img, (int(j[0]), int(j[1])), 4, (0, 0, 255), 2) # 显示有缺陷的针孔
cv2.rectangle(img, (int(j[0] - 25), int(j[1]) - 25), (int(j[0] + 25), int(j[1] + 25)), (0, 0, 255), 2)
is_defect = 1
# for j in range(1, len(line2_yx)):
# if ((abs(line2_yx[j][0]-line2_yx[j-1][0])-pd_1) * DPI) >= wxdis_thres:
# print("第2排点存在不合格: ({},{})".format(str(line2_yx[j][0]), str(line2_yx[j][1])))
# cv2.rectangle(img, (int(line2_yx[j][0] - 25), int(line2_yx[j][1] - 25)), (int(line2_yx[j][0] + 25), int(line2_yx[j][1] + 25)), (0, 0, 255), 2)
# is_defect = 1
else:
print(10*"test")
def takeSecond(elem):
return elem[1]
line2_yx.sort(key=takeSecond)
# pd_1 = (abs(line2_yx[-1][1] - line2_yx[0][1]) / (len(line2_yx) - 1))
# pd_2 = 0
# for pd_i in range(len(line2_yx)):
# if pd_i < len(line2_yx) - 2:
# pd_2 += ((line2_yx[pd_i + 1][1] - line2_yx[pd_i][1]) / (len(line2_yx) - 1))
# pd_3 = (pd_1 + pd_2) / 2 # 判断针孔沿直线方向歪斜的判断标准
# # pd_3 = 80
pd_1, pd_2 = 0, 0
dis_pdi = []
for pd_i in range(len(line1_yx)):
if pd_i < len(line1_yx) - 2:
dis_pdi.append(math.sqrt(pow(line1_yx[pd_i + 1][1] - line1_yx[pd_i][1], 2) + pow(line1_yx[pd_i + 1][0] - line1_yx[pd_i][0], 2)))
# pd_2 += ((line1_yx[pd_i + 1][0] - line1_yx[pd_i][0]) / (len(line1_yx) - 1))
for dis_i in dis_pdi:
pd_1 += (dis_i / len(dis_pdi)) # 平均值
print(pd_1)
ptStart, ptEnd = (int((0-b2)/k2), 0), (int((img.shape[0] - b2) / k2), img.shape[0]) # 坐标点取得整数需要修改***************
cv2.line(img, ptStart, ptEnd, (255, 0, 0), 2)
for j in line2_yx:
distance = abs(j[0] - int((j[1]-b2)/k2))
# 在原图绘制点的偏差值
cv2.putText(img, str(distance[0]), (int(j[0] + 5), int(j[1] + 5)), 0, 2, (0, 255, 0), thickness=3)
if round((distance[0] * DPI), 2) >= 0.05:
annotator1.box_label([int(j[0]), int(j[1]), int(j[0] + 10), int(j[1] + 10)], f'{round((distance[0] * DPI), 2)}', color=(0, 255, 0))
if (distance * DPI) > wxdis_thres:
print("第2排点存在不合格: ({},{})".format(str(j[0]), str(j[1])))
cv2.circle(img, (int(j[0]), int(j[1])), 4, (0, 0, 255), 2) # 显示有缺陷的针孔
cv2.rectangle(img, (int(j[0] - 25), int(j[1]) - 25), (int(j[0] + 25), int(j[1] + 25)), (0, 0, 255), 2)
is_defect = 1
for j in range(1, len(line2_yx)):
if ((abs(line2_yx[j][1] - line2_yx[j - 1][1]) - pd_1) * DPI) >= wxdis_thres:
print("第2排点直线方向存在不合格: ({},{})".format(str(line2_yx[j][0]), str(line2_yx[j][1])))
cv2.rectangle(img, (int(line2_yx[j][0] - 25), int(line2_yx[j][1] - 25)),
(int(line2_yx[j][0] + 25), int(line2_yx[j][1] + 25)), (0, 0, 255), 2)
is_defect = 1
cv2.namedWindow("imgline2", 2) # 显示大分辨率图片
cv2.imshow('imgline2', img)
cv2.waitKey()
cv2.imwrite('./test/lin2.png', img)
return is_defect, img
def lj_img(img):
wlj, hlj = img.shape
lj_dis = 5 # 连接白色区域的判定距离
for ilj in range(wlj-1):
for jlj in range(hlj-1):
if img[ilj, jlj] == 255: # 判断上下左右是否存在白色区域并连通
if ilj-lj_dis >= 0 and img[ilj-lj_dis, jlj] == 255: img[ilj-lj_dis:ilj, jlj]=255
if ilj+lj_dis < wlj and img[ilj+lj_dis, jlj] == 255: img[ilj:ilj+lj_dis, jlj]=255
if jlj-lj_dis >= 0 and img[ilj, jlj-lj_dis] == 255: img[ilj, jlj-lj_dis:jlj] = 255
if jlj+lj_dis < hlj and img[ilj, jlj+lj_dis] == 255: img[ilj, jlj:jlj+lj_dis] = 255
return img
def imgBrightness(img1, c, b):
rows, cols, channels = img1.shape
blank = np.zeros([rows, cols, channels], img1.dtype)
rst = cv2.addWeighted(img1, c, blank, 1 - c, b)
return rst
def mainFigure(img, im0, bc, wxdis_thres, DPI):
# global im_res
params = cv2.SimpleBlobDetector_Params() # 黑色斑点面积大小:1524--1581--1400--周围干扰面积: 1325--1695--1688--
# Filter by Area. 设置斑点检测的参数
params.filterByArea = True # 根据大小进行筛选
params.minArea = 10e2
params.maxArea = 10e4
params.minDistBetweenBlobs = 40 # 设置两个斑点间的最小距离 10*7.5
# params.filterByColor = True # 跟据颜色进行检测
params.filterByConvexity = False # 根据凸性进行检测
params.minThreshold = 30 # 二值化的起末阈值,只有灰度值大于当前阈值的值才会被当成特征值
params.maxThreshold = 30*2.5 # 75
params.filterByColor = True # 检测颜色限制,0黑色,255白色
params.blobColor = 255
params.filterByCircularity = True
params.minCircularity = 0.5
# HSV二值化
# img = cv2.medianBlur(img, 5) # 中值滤波
# cv2.imwrite('Images/dectCircle/source.png', img)
# imgt = imgBrightness(img, 1.3, 1)
# cv2.imwrite('./imgt0.png', imgt)
# img = cv2.cvtColor(imgt, cv2.COLOR_BGR2HSV)
# cv2.imwrite('./imgt.png', imgt)
# alpha = 3 # Contrast control (1.0-3.0)
# beta = 50 # Brightness control (0-100)
# img = cv2.convertScaleAbs(img, alpha=alpha, beta=beta)
# cv2.imwrite('./img_duibidu.png', img)
# # img = cv2.medianBlur(img, 5) # 中值滤波
# img= cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# minThreshValue = 35 # 灰度图片二值化的最小阈值
# _, gray = cv2.threshold(img, minThreshValue, 255, cv2.THRESH_BINARY)
# cv2.imwrite('./gray_hb.png', gray)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# cv2.imshow('Images/dectCircle/HSV.png', hsv)
# cv2.waitKey()
# cv2.imwrite('Images/dectCircle/HSV.png', hsv)
# lower_color = np.array([12, 80, 45]) # 分别对应着HSV中的最小值
# upper_color = np.array([255, 255, 255]) # 分别对应着HSV中的最大值
# gray = cv2.inRange(hsv, lower_color, upper_color) # inrange函数将根据最小最大HSV值检测出自己想要的颜色部分
# cv2.imwrite('./hsv_mask.png', gray)
# 根据RGB阈值黑白化图片
w_hsv, h_hsv = hsv.shape[1], hsv.shape[0]
for i_hsv in range(w_hsv):
for j_hsv in range(h_hsv):
if hsv[j_hsv, i_hsv][0] < 100 and hsv[j_hsv, i_hsv][1] < 100 and hsv[j_hsv, i_hsv][2] > 160:
# if hsv[j_hsv, i_hsv][0] < 100 and hsv[j_hsv, i_hsv][1] < 100 and hsv[j_hsv, i_hsv][2] > 50:
hsv[j_hsv, i_hsv] = 255, 255, 255
else:
hsv[j_hsv, i_hsv] = 0, 0, 0
# cv2.imwrite('Images/dectCircle/HSV_hb.png', hsv)
# cv2.imshow('hsv', hsv)
kernel1 = np.ones((9, 9), dtype=np.uint8)
kernel2 = np.ones((3, 3), dtype=np.uint8)
hsv = cv2.dilate(hsv, kernel1, 1) # 1:迭代次数,也就是执行几次膨胀操作
gray = cv2.erode(hsv, kernel2, 1)
# cv2.imwrite('Images/dectCircle/fushi_pengzhang_gray.png', gray)
gray = cv2.cvtColor(gray, cv2.COLOR_BGR2GRAY)
# cv2.imwrite('Images/dectCircle/fushi_pengzhang_gray2.png', gray)
# cv2.imshow('gray', gray)
# cv2.waitKey()
# 对于连接不完全的区域,进行连接
# gray = lj_img(gray)
# cv2.imwrite('./lj_img.png', gray)
# gray = lj_img(gray)
# cv2.imwrite('./lj_img2.png', gray)
try:
# 使用霍夫圆填充圆形
# gray_circles=cv2.HoughCircles(gray,cv2.HOUGH_GRADIENT,4,56,param1=100,param2=40,minRadius=20,maxRadius=30)
gray_circles=cv2.HoughCircles(gray,cv2.HOUGH_GRADIENT,4,56,param1=100,param2=40,minRadius=12,maxRadius=30)
# # 注意看参数 测试的话 可以把参数卡的死一点
# # dp =4 因为要检测的圆比较小
# # minDist 要检测的圆之间圆心之间的距离 自己目测看吧 越准确越好。。。 如果这个值过大或者过小,会发现很多圆都偏移的厉害(这个算法对设置的参数非常看重,有些地方明明没有圆,只要设置了这个参数,有点的差不多的都给你画出个圆来)
# # param1 是跟着一个教程走的
# # param2 如果你的图中的圆非常标准 这个数就可以大点,越大表示所要检测的圆越标准
# # minRadius和maxRadius就根据自己图的实际情况来定就好
print('霍夫圆个数:', len(gray_circles[0]))
for (x,y,r) in gray_circles[0]:
x=int(x)
y=int(y)
# if 0<x<50 and 100<y<550:
# pass
# else:
# output_circle=cv2.circle(hole_right,(x,y),int(r),(0,0,255),3)
# output=cv2.rectangle(output_circle,(x-2,y-2),(x+2,y+2),(255,255,255),1)
gray = cv2.circle(gray, (x, y), int(r)+3, (255, 255, 255), -1)
# output_circle=cv2.rectangle(output_circle,(x-2,y-2),(x+2,y+2),(255,255,255),1)
# cv2.imwrite('Images/dectCircle/img_hf.jpg', gray)
# cv2.imshow('img_hf.jpg', gray)
# cv2.waitKey()
except:
params0 = cv2.SimpleBlobDetector_Params() # 黑色斑点面积大小:1524--1581--1400--周围干扰面积: 1325--1695--1688--
# Filter by Area. 设置斑点检测的参数
params0.filterByArea = True # 根据大小进行筛选
params0.minArea = 10e2
params0.maxArea = 10e3
params0.minDistBetweenBlobs = 40 # 设置两个斑点间的最小距离 10*7.5
params0.filterByConvexity = False # 根据凸性进行检测
params0.minThreshold = 30 # 二值化的起末阈值,只有灰度值大于当前阈值的值才会被当成特征值
params0.maxThreshold = 30 * 2.5 # 75
params0.filterByColor = True # 检测颜色限制,0黑色,255白色
params0.blobColor = 0
params0.filterByCircularity = True
params0.minCircularity = 0.5
detector0 = cv2.SimpleBlobDetector_create(params0)
keypoints0 = list(detector0.detect(gray))
for poi0 in keypoints0: # 回归到原大图坐标系
x_poi0, y_poi0 = poi0.pt[0], poi0.pt[1]
gray = cv2.circle(gray, (int(x_poi0), int(y_poi0)), 20, (255, 255, 255), -1)
cv2.imwrite('Images/dectCircle/img_blob.jpg', gray)
# 找到距离原点(0,0)最近和最远的点
detector = cv2.SimpleBlobDetector_create(params)
keypoints = list(detector.detect(gray))
w0, h0 = img.shape[1], img.shape[0]
del_dis = 17
for poi in keypoints: # 回归到原大图坐标系
x_poi, y_poi = poi.pt[0], poi.pt[1]
if abs(x_poi - w0)<del_dis or abs(y_poi - h0)<del_dis or x_poi<del_dis or y_poi<del_dis:
x_poi, y_poi = 0, 0
else:
x_poi += bc[0]
y_poi += bc[1]
poi.pt = (x_poi, y_poi)
im_with_keypoints = cv2.drawKeypoints(im0, keypoints, np.array([]), (0, 0, 255), cv2.DRAW_MATCHES_FLAGS_DEFAULT) # 在原图绘制圆心点
cv2.imwrite('Images/dectCircle/im_with_keypoints.png', im_with_keypoints)
allCirclesCenter = [] # 保存所有孔的圆心
if keypoints is not None:
for i in range(len(keypoints)):
if keypoints[i].pt[0] and keypoints[i].pt[1]:
allCirclesCenter.append(keypoints[i].pt)
is_defect = 0 # 判断插针是否歪斜,在原图画线并且显示偏离距离
if len(allCirclesCenter) > 5:
is_defect, im0 = drawLines(im0, allCirclesCenter, wxdis_thres, DPI)
# cv2.namedWindow("im_res", cv2.WINDOW_NORMAL) # 显示大分辨率图片
# cv2.imshow('im_res', im0)
# cv2.waitKey(0)
im_res = cv2.drawKeypoints(im0, keypoints, np.array([]), (0, 0, 255), cv2.DRAW_MATCHES_FLAGS_DEFAULT) # 在原图绘制圆心点
# cv2.imwrite('./test/final_.png', im_res)
# cv2.namedWindow("im_res", cv2.WINDOW_NORMAL) # 显示大分辨率图片
# cv2.imshow('im_res', im_res)
# cv2.waitKey(0)
return is_defect, im_res
if __name__ == "__main__":
# # two j599
# DPI = 0.019553336388862412
# im0 = cv2.imread("1102/J30JHole.jpeg", 1)
# im_area = im0[1090:1435, 1222:2203] # Y0:Y1,X0:X1
# is_defect, im0 = mainFigure(im_area, im0, [1222, 1090], 0.05, DPI)
# # two j30j
im0 = cv2.imread("Images/Final/A_0_1.jpg", 1)
im_area = im0[1322:1756, 2205:2620] # Y0:Y1,X0:X1
# cv2.imwrite('./test/im_area.png', im_area)
is_defect, im0 = mainFigure(im_area, im0, [2205, 1322], 0.05, 0.0103)
# cv2.imwrite("Images/dectCircle/imres.jpg", im0)
# # 所有图片测试
# for i in range(17):
# fileName = "Hole" + str(i+1) + ".jpg"
# # img = cv2.imread("circles/Snap_007.jpg",1)
# img = cv2.imread("images/Holes/" + fileName,1)
# print(fileName)
# mainFigure(img)
# im0 = cv2.imread("Images/Final/A_0_1.jpg", 1)
# im_area = im0[1322:1756, 2205:2620] # Y0:Y1,X0:X1
# for __ in range(10):
# # cv2.imwrite('./test/im_area.png', im_area)
# is_defect, im0 = mainFigure(im_area, im0, [2205, 1322], 0.05, 0.0103)