检测两排孔并拟合直线测孔间距2

用随机采样一致性处理后拟合直线效果会更好

# 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)


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值