opencv python

pyhton 用红色的线把 这个黑 三角形框出? 注意有干扰 (十字) ?

img

花了点时间用c++实现了一下,核心就是使用霍夫直线检测即可

#include<opencv2/opencv.hpp>
#include<iostream>
#include "MatTool.hpp"
using namespace std;
using namespace cv;
//删除大面积的连通域
Mat deleteMaxArea(Mat src, int max_area) {
    Mat labels, stats, centroids, img_color, grayImg;
    //1、连通域信息统计
    int nccomps = connectedComponentsWithStats(
        src, //二值图像
        labels,
        stats,
        centroids
    );

    //2、连通域状态区分
    //为每一个连通域初始化颜色表
    vector<Vec3b> colors(nccomps);
    colors[0] = Vec3b(0, 0, 0); // background pixels remain black.
    for (int i = 1; i < nccomps; i++)
    {
        colors[i] = Vec3b(rand() % 256, rand() % 256, rand() % 256);
        //面积阈值筛选
        if ((stats.at<int>(i, CC_STAT_AREA) > max_area))
        {
            //如果连通域面积不合格则置黑
            colors[i] = Vec3b(0, 0, 0);
        }
    }
    //3、连通域删除
    //按照label值,对不同的连通域进行着色
    img_color = Mat::zeros(src.size(), CV_8UC3);
    for (int y = 0; y < img_color.rows; y++)
    {
        int* labels_p = labels.ptr<int>(y);//使用行指针,加速运算
        Vec3b* img_color_p = img_color.ptr<Vec3b>(y);//使用行指针,加速运算
        for (int x = 0; x < img_color.cols; x++)
        {
            int label = labels_p[x];//取出label值
            CV_Assert(0 <= label && label <= nccomps);
            img_color_p[x] = colors[label];//设置颜色
        }
    }
    //return img_color;
    //如果是需要二值结果则将img_color进行二值化
    cvtColor(img_color, grayImg, COLOR_BGR2GRAY);
    threshold(grayImg, grayImg, 1, 255, THRESH_BINARY);
    return grayImg;
}
void main(int argc, char** argv)
{
    //1. 读取图像
    Mat src, canny, dst;
    src = imread("C:/Users/hpg/Pictures/c.jpg",0);
    imshow("src", src);

    //2. 获取边缘
    Canny(src, canny, 100, 200);
    //3. 转成灰度图像
    cvtColor(canny, dst, COLOR_GRAY2BGR);//将二值图转换为RGB图颜色空间,这里重新创建一张空Mat也行
    //4. 霍夫变换检测
    vector<Vec4f> plines;//保存霍夫变换检测到的直线
    HoughLinesP(canny, plines, 1, CV_PI / 180, 10, 10, 50);//提取边缘时,会造成有些点不连续,所以maxLineGap设大点
    //5. 显示检测到的直线
    Scalar color = Scalar(0, 0, 255);//设置颜色
    Mat whate = Mat::ones(Size(src.cols, src.rows),CV_8UC1)*255;
    for (size_t i = 0; i < plines.size(); i++)
    {
        Vec4f hline = plines[i];
        line(dst, Point(hline[0], hline[1]), Point(hline[2], hline[3]), color, 3, LINE_AA);//绘制直线
        line(whate, Point(hline[0], hline[1]), Point(hline[2], hline[3]), color, 3, LINE_AA);//绘制直线
    }
    Mat triangle = deleteMaxArea(whate, whate.cols*whate.rows/10);
    //imshow("triangle", triangle);
    //imshow("plines", dst);
    //imshow("zeros", whate);
    //imshow("canny", canny);
    imshows("canny-plines-zeros-triangle", { src,canny,whate,triangle },2);
    waitKey(0);
}

img

可以使用 OpenCV 这个库来实现。首先,你需要导入 OpenCV 库和 NumPy 库,然后载入图片,使用 Canny 边缘检测算法来检测图片中的边缘。

接着,你可以使用 HoughLinesP 函数来检测图片中的直线。这个函数会返回直线的端点坐标,你可以根据这些坐标来绘制红色线来框出三角形。

import cv2
import numpy as np

# 载入图片
img = cv2.imread('image.jpg')

# 预处理,使用 Canny 边缘检测算法检测边缘
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 50, 150)

# 检测直线
lines = cv2.HoughLinesP(edges, 1, np.pi/180, 100, minLineLength=100, maxLineGap=10)

# 遍历检测到的直线
for line in lines:
    x1, y1, x2, y2 = line[0]
    # 绘制红色线来框出三角形
    cv2.line(img, (x1, y1), (x2, y2), (0, 0, 255), 2)

# 显示结果
cv2.imshow("result", img)
cv2.waitKey(0)
cv2.destroyAllWindows()

然而,由于存在干扰,很难通过这种方式准确的框出三角形,可能需要更细致的算法和参数调整或者其他方式来解决。

例如,使用轮廓检测算法或者形态学算法来提取三角形的轮廓,并在基于轮廓提取出来的三角形的顶点坐标来绘制红色线来框出三角形。

例如使用 cv2.findContours() 来提取轮廓,然后通过筛选面积合适的三角形轮廓,提取三角形的顶点坐标并绘制红色线来框出三角形。

代码如下:

import cv2
import numpy as np

# 载入图片
img = cv2.imread('image.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)[1]

cnts = cv2.findContours(thresh, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]

for c in cnts:
    # 判断是否是三角形
    if len(c) == 3:
        # 提取三角形的顶点坐标
        x1, y1 = c[0][0]
        x2, y2 = c[1][0]
        x3, y3 = c[2][0]
        # 绘制红色线来框出三角形
        cv2.line(img, (x1, y1), (x2, y2), (0, 0, 255), 2)
        cv2.line(img, (x2, y2), (x3, y3), (0, 0, 255), 2)
        cv2.line(img, (x3, y3), (x1, y1), (0, 0, 255), 2)

# 显示结果
cv2.imshow("result", img)
cv2.waitKey(0)
cv2.destroyAllWindows()

这种方式可能不能完全消除干扰,但是能够更好的框出三角形。

通过 OpenCV 提取三角框,这并不难。
但是,你要想清楚你真正的问题是什么。
什么意思呢?就是你认为的检测目标(三角形)与干扰图案(十字)的显著区别是什么?是直线,还是顶点,还是什么?
如果说不要讨论区别,只要对这个图框出三角形就可以,那就直接用鼠标标出顶点,连成直线不就行了?

通常问这类问题,至少需要给出5种显著不同的典型测试用图。
比如:
三角形的大小是否变化,变化范围是?
三角形的旋转角度是否变化,变化范围是?
三角形的形状是否变化,变化范围是?(任意三角形/等腰三角形/直角三角形/……)
十字干扰的粗细是否变化,变化范围是?
十字干扰的旋转角度是否变化,变化范围是?
十字干扰的数量是否变化,变化范围是?

参考:
程序员的基本素质---树上还剩几只鸟
https://blog.csdn.net/weixin_34248258/article/details/91508428
(^_^)