2023电赛E题OpenCV获取矩形框和光斑坐标

import cv2
import numpy as np


#-----------找光斑函数----------------
def Find_red(frame):
    x = 0
    y = 0
    # 进行高斯模糊
    blurred = cv2.GaussianBlur(frame, (11, 11), 0)
    # 转换颜色空间到HSV
    hsv = cv2.cvtColor(blurred, cv2.COLOR_BGR2HSV)
    # ---------白纸 白板上的红色激光阈值
    lower_red = np.array([133, 12, 0])
    upper_red = np.array([179, 255, 255])
    # 对图片进行二值化处理
    mask = cv2.inRange(hsv, lower_red, upper_red)
    # 腐蚀操作
    mask = cv2.erode(mask, None, iterations=2)
    # 膨胀操作,先腐蚀后膨胀以滤除噪声
    mask = cv2.dilate(mask, None, iterations=2)
    cv2.imshow('mask', mask)

   # 寻找图中轮廓
    cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2]
    # 如果存在至少一个轮廓则进行如下操作
    if len(cnts) > 0:
        # 找到面积最大的轮廓
        c = max(cnts, key=cv2.contourArea)
        # 使用最小外接圆圈出面积最大的轮廓
        ((x, y), radius) = cv2.minEnclosingCircle(c)

        print('光斑位置:', x, y)
        # 计算轮廓的矩
        M = cv2.moments(c)
        # 计算轮廓的重心
        center = (int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"]))# 通过矩计算中心xy坐标

        # 只处理尺寸足够大的轮廓
        if radius > 5:
            # 画出最小外接圆
            cv2.circle(frame, (int(x), int(y)), int(radius), (0, 255, 255), 2)
            # 画出重心
            cv2.circle(frame, center, 2, (0, 0, 255), -1)

    # cv2.imshow('frame', frame)
    return x, y


#---------绘制需要的边缘到空白图像-----------
def find_Contours(original_image, img, edge_img1, cunt):
    co = []
    contours, _ = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
    # 遍历边缘,仅绘制满足面积条件的边缘
    for contour in contours:
        # 找到面积最大的轮廓
        c = max(contours, key=cv2.contourArea)
        # 对轮廓进行多边形近似,减少点数
        epsilon = 0.02 * cv2.arcLength(c, True)
        approx = cv2.approxPolyDP(c, epsilon, True)
        # 确保近似后的轮廓是四边形
        if len(approx) == 4:
            # 获取矩形的四个角坐标
            co = approx.reshape(-1, 2)
            # 在原图上绘制四个角点
            for corner in co:
                x, y = corner
                cv2.circle(original_image, (x, y), 5, (0, 255, 0), -1)

        area = cv2.contourArea(contour)
        if 5000 < area < 9500:  # 面积大小 根据实际情况调
            # 将满足条件的边缘绘制在空白图像上
            cv2.drawContours(edge_img1, [contour], -1, 255, 1)
            break
    return co

def get_distance(dian):
    distances = []
    for i in range(len(dian)):
        for j in range(i + 1, len(dian)):
            x1, y1 = dian[i]
            x2, y2 = dian[j]
            distance = np.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
            distances.append(distance)
    return distances

def Get_linspa(data1, data2):
    X = []
    Y = []
    # 将两个点作为数据点,创建 NumPy 数组
    x_data = np.array([data1[0], data2[0]])
    y_data = np.array([data1[1], data2[1]])
    # 使用 np.polyfit 进行线性回归计算
    coefficients = np.polyfit(x_data, y_data, 1)
    # 得到拟合直线的斜率和截距
    slope = coefficients[0]
    intercept = coefficients[1]
    # 使用斜率和截距来求出直线上的其他点的坐标
    x_values_top = np.linspace(start=data1[0], stop=data2[0], num=10)
    y_values_top = slope * x_values_top + intercept
    # 输出拟合直线的斜率和截距
    print(x_values_top)
    print("斜率:", slope)
    print("截距:", intercept)
    # 输出拟合直线上的其他点的坐标
    print("拟合直线上的点坐标:")
    for x, y in zip(x_values_top, y_values_top):
        print("({:.2f}, {:.2f})".format(x, y))
        X.append(x)
        Y.append(y)

    return X, Y, slope

def control_system(big_, small_, rx, ry, state=0):
    #得到内外矩形框四角坐标
    left_top1 = big_[0]  #外边框
    left_down1 = big_[1]
    right_down1 = big_[2]
    right_top1 = big_[3]

    left_top2 = small_[0]   #内边框
    left_down2 = small_[1]
    right_down2 = small_[2]
    right_top2 = small_[3]

    left_top = (left_top2+left_top1)/2 #两框之间位置的四个角
    left_down = (left_down2+left_down1)/2
    right_down = (right_down2+right_down1)/2
    right_top = (right_top2+right_top1)/2

    #拟合黑线之间的四条边  得到的xy和斜率
    left_outx, left_outy, left_slope = Get_linspa(left_top, left_down)
    down_outx, down_outy, down_slope = Get_linspa(left_down, right_down)
    right_outx, right_outy, right_slope = Get_linspa(right_down, right_top)
    right_outx.reverse()#逆排序
    right_outy.reverse()
    top_outx, top_outy, top_slope = Get_linspa(right_top, left_top)
    print(left_outx, left_outy)
    print(down_outx, down_outy)
    print(right_outx, right_outy)
    print(top_outx, top_outy)

    return left_top, left_down, right_down, right_top, left_slope, down_slope, right_slope, top_slope

def Canny_detect():
    out_d = []
    in_d = []
    flag_findbleak = 1
    # 打开摄像头
    capture = cv2.VideoCapture(1, cv2.CAP_DSHOW)  # 0:本地摄像头    1:外接摄像头

    while(True):
        # 1、按帧读取视频
        ret, frame = capture.read()  # frame为每一帧的图像
        # 检查图像是否成功加载
        if ret is False:
            print("Error: Failed to load the image.")
        else:
            # 检测矩形框 两个
            if flag_findbleak == 1:
                #-------边缘提取
                # 3、高斯滤波 Canny边缘算子
                img = cv2.GaussianBlur(frame, (3, 3), 0)  # 用高斯平滑处理原图像降噪。
                canny = cv2.Canny(img, threshold1=100, threshold2=250, L2gradient=True)  # 得到边缘

                # 4. 查找轮廓
                #方法1 5. 绘制满足面积条件的边缘
                cunt = 0#判断是大还是小边缘
                edge_img1 = np.zeros_like(canny)# 创建空白图像
                big_ = find_Contours(img, canny, edge_img1, cunt)#外边缘
                print('大---',big_)    #左上 左下  右下 右上
                cunt = cunt+1
                canny2 = canny - edge_img1   #原始边缘图减去大方框
                small_ = find_Contours(img, canny2, edge_img1, cunt) #再找一个方框(内边缘)
                print('小----', small_)
                # 计算每个点之间的距离
                big_dis = get_distance(big_)
                small_dis = get_distance(small_)
                #
                print("每个点之间的距离:")
                print(big_dis)
                print(small_dis)

                if len(big_dis)>0 and len(small_dis)>0:
                    if big_dis != small_dis:
                        out_d = big_
                        in_d = small_
                        # flag_findbleak = 0
                        # cv2.imwrite('photo.jpg', img)

                # cv2.imshow("canny", canny)
                cv2.imshow("img", img)

            #开始检测光斑
            elif flag_findbleak == 0:
                img = cv2.GaussianBlur(frame, (3, 3), 0)  # 用高斯平滑处理原图像降噪。
                # 光斑的xy坐标
                red_x, red_y = Find_red(img)
                # 黑框里面的四个角坐标
                left_top, left_down, right_down, right_top, left_slope, down_slope, right_slope, top_slope = control_system(out_d, in_d, red_x, red_y, 0)
                cv2.imshow("find_red", img)
                if red_x!=0 and red_y!=0:
                    with open('data.txt', 'w') as file:
                        file.write('red_xy:')
                        file.write(str(red_x)+', ')
                        file.write(str(red_y))

                        file.write('\n' + 'left_top_xy:')
                        for item in left_top:
                            file.write(str(item) + '\n')

                        file.write('left_down_xy:')
                        for item in left_down:
                            file.write(str(item) + '\n')

                        file.write('right_down_xy:')
                        for item in right_down:
                            file.write(str(item) + '\n')

                        file.write('right_top_xy:')
                        for item in right_top:
                            file.write(str(item) + '\n')

                        file.write('left_slope:'+str(left_slope)+' ')
                        file.write('down_slope:' + str(down_slope)+' ')
                        file.write('right_slope:' + str(right_slope)+' ')
                        file.write('top_slope:' + str(top_slope)+' ')
                    break



        # esc键退出(设置读帧间隔时间)
        c = cv2.waitKey(5)
        if c == 27:  # ESC
            break

if __name__ == "__main__":
    i = 0
    Canny_detect()
    cv2.waitKey(0)
    cv2.destroyAllWindows()

  • 2
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值