精华内容
下载资源
问答
  • 检测矩形 用java opencv检测矩形
  • 解决opencv检测矩形框无法显示中文的现象 前段时间做过一个人脸识别的项目,刚开始做的时候发现了一个问题,就是当检测到目标人脸时,它的检测矩形框内只能出现英文,而当改成中文时会出现乱码的现象,所以在很多...

    解决opencv检测矩形框无法显示中文的现象

    前段时间做过一个人脸识别的项目,刚开始做的时候发现了一个问题,就是当检测到目标人脸时,它的检测矩形框内只能出现英文,而当改成中文时会出现乱码的现象,所以在很多场景下,会极大的影响用户体验,当检测出人脸时,无法显示中文人名。

    参考代码展示

    这是主文件的所有代码

    import cv2
    import os
    import numpy as np
    from net.mtcnn import mtcnn
    import utils.utils as utils
    from net.inception import InceptionResNetV1
    
    
    class face_rec():
        def __init__(self):
            # 创建mtcnn对象
            # 检测图片中的人脸
            self.mtcnn_model = mtcnn()
            # 门限函数
            self.threshold = [0.5, 0.8, 0.9]
    
            # 载入facenet
            # 将检测到的人脸转化为128维的向量
            self.facenet_model = InceptionResNetV1()
            # model.summary()
            model_path = './model_data/facenet_keras.h5'
            self.facenet_model.load_weights(model_path)
    
            # -----------------------------------------------#
            #   对数据库中的人脸进行编码
            #   known_face_encodings中存储的是编码后的人脸
            #   known_face_names为人脸的名字
            # -----------------------------------------------#
            face_list = os.listdir("face_dataset")
    
            self.known_face_encodings = []
    
            self.known_face_names = []
    
            for face in face_list:
                name = face.split(".")[0]
    
                img = cv2.imread("./face_dataset/" + face)
                img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    
                # 检测人脸
                rectangles = self.mtcnn_model.detectFace(img, self.threshold)
    
                # 转化成正方形
                rectangles = utils.rect2square(np.array(rectangles))
                # facenet要传入一个160x160的图片
                rectangle = rectangles[0]
                # 记下他们的landmark
                landmark = (np.reshape(rectangle[5:15], (5, 2)) - np.array([int(rectangle[0]), int(rectangle[1])])) / (
                            rectangle[3] - rectangle[1]) * 160
    
                crop_img = img[int(rectangle[1]):int(rectangle[3]), int(rectangle[0]):int(rectangle[2])]
                crop_img = cv2.resize(crop_img, (160, 160))
    
                new_img, _ = utils.Alignment_1(crop_img, landmark)
    
                new_img = np.expand_dims(new_img, 0)
                # 将检测到的人脸传入到facenet的模型中,实现128维特征向量的提取
                face_encoding = utils.calc_128_vec(self.facenet_model, new_img)
    
                self.known_face_encodings.append(face_encoding)
                self.known_face_names.append(name)
    
        def recognize(self, draw):
            # -----------------------------------------------#
            #   人脸识别
            #   先定位,再进行数据库匹配
            # -----------------------------------------------#
            height, width, _ = np.shape(draw)
            draw_rgb = cv2.cvtColor(draw, cv2.COLOR_BGR2RGB)
    
            # 检测人脸
            rectangles = self.mtcnn_model.detectFace(draw_rgb, self.threshold)
            print(np.shape(rectangles))
            if len(rectangles) == 0:
                return
    
            # 转化成正方形
            rectangles = utils.rect2square(np.array(rectangles, dtype=np.int32))
            rectangles[:, 0] = np.clip(rectangles[:, 0], 0, width)
            rectangles[:, 1] = np.clip(rectangles[:, 1], 0, height)
            rectangles[:, 2] = np.clip(rectangles[:, 2], 0, width)
            rectangles[:, 3] = np.clip(rectangles[:, 3], 0, height)
            # -----------------------------------------------#
            #   对检测到的人脸进行编码
            # -----------------------------------------------#
            face_encodings = []
            for rectangle in rectangles:
                # 获取landmark在小图中的坐标
                landmark = (np.reshape(rectangle[5:15], (5, 2)) - np.array([int(rectangle[0]), int(rectangle[1])])) / (
                            rectangle[3] - rectangle[1]) * 160
                # 截取图像
                crop_img = draw_rgb[int(rectangle[1]):int(rectangle[3]), int(rectangle[0]):int(rectangle[2])]
                crop_img = cv2.resize(crop_img, (160, 160))
                # 对齐
                new_img, _ = utils.Alignment_1(crop_img, landmark)
                new_img = np.expand_dims(new_img, 0)
                # 利用facenet_model计算128维特征向量
                face_encoding = utils.calc_128_vec(self.facenet_model, new_img)
                face_encodings.append(face_encoding)
    
            face_names = []
            for face_encoding in face_encodings:
                # 取出一张脸并与数据库中所有的人脸进行对比,计算得分
                matches = utils.compare_faces(self.known_face_encodings, face_encoding, tolerance=0.9)
                name = "Unknown"
                # 找出距离最近的人脸
                face_distances = utils.face_distance(self.known_face_encodings, face_encoding)
                # 取出这个最近人脸的评分
                best_match_index = np.argmin(face_distances)
                if matches[best_match_index]:
                    name = self.known_face_names[best_match_index]
                face_names.append(name)
    
            rectangles = rectangles[:, 0:4]
            # -----------------------------------------------#
            #   画框~!~
            # -----------------------------------------------#
            for (left, top, right, bottom), name in zip(rectangles, face_names):
                cv2.rectangle(draw, (left, top), (right, bottom), (0, 0, 255), 2)
    
                font = cv2.FONT_HERSHEY_SIMPLEX
                cv2.putText(draw, name, (left, bottom - 15), font, 0.75, (255, 255, 255), 2)
            return draw
    
    
    if __name__ == "__main__":
    
        dududu = face_rec()
        video_capture = cv2.VideoCapture(1)
    
        while True:
            ret, draw = video_capture.read()
            dududu.recognize(draw)
            cv2.imshow('Video', draw)
            if cv2.waitKey(20) & 0xFF == ord('q'):
                break
    
        video_capture.release()
        cv2.destroyAllWindows()

    修改后代码

    import cv2
    import os
    import numpy as np
    from net.mtcnn import mtcnn
    import utils.utils as utils
    from net.inception import InceptionResNetV1
    from PIL import Image,ImageDraw,ImageFont
    
    
    def change_cv2_draw(image,name,local,sizes,colour):
    
        if (isinstance(image, np.ndarray)):  #判断是否OpenCV图片类型
            pil_img = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
        draw1 = ImageDraw.Draw(pil_img)  # 图片上打印
        font = ImageFont.truetype("SIMLI.TTF",sizes, encoding="utf-8")
        draw1.text(local, name, colour, font=font)
        #PIL转opencv
        image = cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2BGR)
        return image
    
    class face_rec():
        def __init__(self):
            # 创建mtcnn对象
            # 检测图片中的人脸
            self.mtcnn_model = mtcnn()
            # 门限函数
            self.threshold = [0.5,0.8,0.9]
    
            # 载入facenet
            # 将检测到的人脸转化为128维的向量
            self.facenet_model = InceptionResNetV1()
            # model.summary()
            model_path = './model_data/facenet_keras.h5'
            self.facenet_model.load_weights(model_path)
    
            #-----------------------------------------------#
            #   对数据库中的人脸进行编码
            #   known_face_encodings中存储的是编码后的人脸
            #   known_face_names为人脸的名字
            #-----------------------------------------------#
            face_list = os.listdir("face_dataset")
    
            self.known_face_encodings=[]
    
            self.known_face_names=[]
    
            for face in face_list:
                name = face.split(".")[0]
    
                #img = cv2.imread("./face_dataset/"+face)
                #img = cv2.imdecode(np.fromfile("./face_dataset/"+face, dtype=np.uint8), -1)
                img=cv2.imdecode(np.fromfile("./face_dataset/"+face, dtype=np.uint8),cv2.IMREAD_COLOR)
                img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
    
                # 检测人脸
                rectangles = self.mtcnn_model.detectFace(img, self.threshold)
    
                # 转化成正方形
                rectangles = utils.rect2square(np.array(rectangles))
                # facenet要传入一个160x160的图片
                rectangle = rectangles[0]
                # 记下他们的landmark
                landmark = (np.reshape(rectangle[5:15],(5,2)) - np.array([int(rectangle[0]),int(rectangle[1])]))/(rectangle[3]-rectangle[1])*160
    
                crop_img = img[int(rectangle[1]):int(rectangle[3]), int(rectangle[0]):int(rectangle[2])]
                crop_img = cv2.resize(crop_img,(160,160))
    
                new_img,_ = utils.Alignment_1(crop_img,landmark)
    
                new_img = np.expand_dims(new_img,0)
                # 将检测到的人脸传入到facenet的模型中,实现128维特征向量的提取
                face_encoding = utils.calc_128_vec(self.facenet_model,new_img)
    
                self.known_face_encodings.append(face_encoding)
                self.known_face_names.append(name)
    
    
        def recognize(self,draw):
            #-----------------------------------------------#
            #   人脸识别
            #   先定位,再进行数据库匹配
            #-----------------------------------------------#
            height,width,_ = np.shape(draw)
            draw_rgb = cv2.cvtColor(draw,cv2.COLOR_BGR2RGB)
            # 检测人脸
            rectangles = self.mtcnn_model.detectFace(draw_rgb, self.threshold)
    
            if len(rectangles)==0:
                return
    
            # 转化成正方形
            rectangles = utils.rect2square(np.array(rectangles,dtype=np.int32))
            rectangles[:,0] = np.clip(rectangles[:,0],0,width)
            rectangles[:,1] = np.clip(rectangles[:,1],0,height)
            rectangles[:,2] = np.clip(rectangles[:,2],0,width)
            rectangles[:,3] = np.clip(rectangles[:,3],0,height)
            #-----------------------------------------------#
            #   对检测到的人脸进行编码
            #-----------------------------------------------#
            face_encodings = []
            for rectangle in rectangles:
                landmark = (np.reshape(rectangle[5:15],(5,2)) - np.array([int(rectangle[0]),int(rectangle[1])]))/(rectangle[3]-rectangle[1])*160
    
                crop_img = draw_rgb[int(rectangle[1]):int(rectangle[3]), int(rectangle[0]):int(rectangle[2])]
                crop_img = cv2.resize(crop_img,(160,160))
    
                new_img,_ = utils.Alignment_1(crop_img,landmark)
                new_img = np.expand_dims(new_img,0)
    
                face_encoding = utils.calc_128_vec(self.facenet_model,new_img)
                face_encodings.append(face_encoding)
    
            face_names = []
            for face_encoding in face_encodings:
                # 取出一张脸并与数据库中所有的人脸进行对比,计算得分
                matches = utils.compare_faces(self.known_face_encodings, face_encoding, tolerance = 0.9)
                name = "我不认识你"
                # 找出距离最近的人脸
                face_distances = utils.face_distance(self.known_face_encodings, face_encoding)
                # 取出这个最近人脸的评分
                best_match_index = np.argmin(face_distances)
                if matches[best_match_index]:
                    name = self.known_face_names[best_match_index]
                face_names.append(name)
    
            rectangles = rectangles[:,0:4]
            #-----------------------------------------------#
            #   画框~!~
            #-----------------------------------------------#
            for (left, top, right, bottom), name in zip(rectangles, face_names):
                cv2.rectangle(draw, (left, top), (right, bottom), (0, 0, 255), 2)
                #font=ImageFont.truetype('simhei.ttf',10,encoding="utf-8")
                #font = cv2.FONT_HERSHEY_SIMPLEX
                draw=change_cv2_draw(draw, name, (left, bottom - 30), 25, (255, 0, 0))
                #cv2.putText(draw, name, (left, bottom - 15), font, 0.75, (255, 255, 255), 2)
                cv2.imshow("video", draw)
                return draw
    
    if __name__ == "__main__":
    
        dududu = face_rec()
        video_capture = cv2.VideoCapture(0)
    
        while True:
            ret, draw = video_capture.read()
            dududu.recognize(draw)
            #cv2.imshow('Video', draw)
            if cv2.waitKey(20) & 0xFF == ord('q'):
                break
    
        video_capture.release()
        cv2.destroyAllWindows()
    
    

    主要修改点

    1 解决路径存在中文情况下图片读取
    由于我的数据库中图片名称很多都是由中文命名的,放的是一些同学的人脸,嘻嘻! 然后再读取的报错中会报错,不能读取中文路径。
    我把原来的:

    img = cv2.imread("./face_dataset/"+face)

    OpenCV下读取英文路径,改成了:

    img=cv2.imdecode(np.fromfile("./face_dataset/"+face, dtype=np.uint8),cv2.IMREAD_COLOR)

    当然,这个也是可以的:

    img = cv2.imdecode(np.fromfile("./face_dataset/"+face, dtype=np.uint8), -1)

    有好几种方法,看看自己喜欢用哪种,当然这样修改后,不但可以读取中文路径的图片,全是英文路径的同样适用。
    2 opencv与PIL的转换
    主要思路是,先将原来的cv2格式转化为PIL格式,由于PIL库支持中文输入,所以转化为PIL图片后写上中文,再将PIL图片转为cv2格式。
    先定义了一个转化函数:

    def change_cv2_draw(image,name,local,sizes,colour):
    
        if (isinstance(image, np.ndarray)):  #判断是否OpenCV图片类型
            pil_img = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
        draw1 = ImageDraw.Draw(pil_img)  # 图片上打印
        font = ImageFont.truetype("SIMLI.TTF",sizes, encoding="utf-8")
        draw1.text(local, name, colour, font=font)
        image = cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2BGR)
        return image

    调用函数:

    draw=change_cv2_draw(draw, name, (left, bottom - 30), 25, (255, 0, 0))

    补充

    可能细心的同学发现了:

            for (left, top, right, bottom), name in zip(rectangles, face_names):
                cv2.rectangle(draw, (left, top), (right, bottom), (0, 0, 255), 2)
                #font=ImageFont.truetype('simhei.ttf',10,encoding="utf-8")
                #font = cv2.FONT_HERSHEY_SIMPLEX
                draw=change_cv2_draw(draw, name, (left, bottom - 30), 25, (255, 0, 0))
                #cv2.putText(draw, name, (left, bottom - 15), font, 0.75, (255, 255, 255), 2)
                cv2.imshow("video", draw)
                return draw
    
    if __name__ == "__main__":
    
        dududu = face_rec()
        video_capture = cv2.VideoCapture(0)
    
        while True:
            ret, draw = video_capture.read()
            dududu.recognize(draw)
            #cv2.imshow('Video', draw)
            if cv2.waitKey(20) & 0xFF == ord('q'):
                break
    
        video_capture.release()
        cv2.destroyAllWindows()

    我把cv2.imshow(“video”, draw)从下面的主函数下改到了上面,因为当这句代码还是放在下面的时候,边框是不会出现文字的(乱码也不会出现)。还有就是,我在代码里面设置了一些参数,都是凭个人喜好,检测矩形框内的字体颜色,大小,字体都可以自己设置,只要不超过范围,还是可以玩一玩的。

    展开全文
  • opencv检测矩形

    2021-03-19 13:59:03
    依次提取不同的颜色通道(BGR)检测矩形; 3.对每一通道使用canny检测边缘或者使用多个阈值二值化; 4.使用findContours函数查找轮廓; 5.使用approxPolyDP函数去除多边形轮廓一些小的波折; 6.找到同时满足面积较大...

    参考:https://blog.csdn.net/matt45m/article/details/95753563

    1.得到原始图像之后,代码处理的步骤是:
    (1)滤波增强边缘。
    (2)分离图像通道,并检测边缘。
    (3) 提取轮廓。
    (4)使用图像轮廓点进行多边形拟合。
    (5)计算轮廓面积并得到矩形4个顶点。
    (6)求轮廓边缘之间角度的最大余弦。
    (7)画出矩形。

     

    一、首先介绍几个本文用到的函数:
    1、mixChannels()函数
    用途:用于将输入数组的指定通道复制到输出数组的指定通道。

    mixChannels()参数说明:

    void mixChannels(
    const Mat* src, //输入数组或向量矩阵,所有矩阵的大小和深度必须相同。
    size_t nsrcs, //矩阵的数量
    Mat* dst, //输出数组或矩阵向量,大小和深度必须与src[0]相同
    size_t ndsts,//矩阵的数量
    const int* fromTo,//指定被复制通道与要复制到的位置组成的索引对
    size_t npairs //fromTo中索引对的数目
    );
    示例:HSV通道获取

    在HSV颜色空间中: 
    色相 (Hue):代表色彩。取 0 到 360 度的数值来衡量(红-黄-绿-青-蓝-洋红)。 
    饱和度 (Saturation):又称色度,指色彩的深浅,饱和度代表灰色与色调的比例,并以 0% (灰色) 到 100% (完全饱和) 来衡量;S = 0时只有灰度。 
    色调 (Value):色彩的明亮程度。V=1。它包含RGB模型中的R=1,G=1,B=1 三个面,所代表的颜色较亮。

    利用mixChannels()函数通过复制指定通道可以看到HSV颜色空间下的三个通道的具体情况。

    #include<opencv2/opencv.hpp>
    using namespace cv;
     
    int main()
    {
        Mat src, hsv, dst;
        src = imread("1.jpg");
        if (src.empty())
        {
            printf("can not load image \n");
            return -1;
        }
        namedWindow("input", WINDOW_AUTOSIZE);  
        imshow("input", src);
        cvtColor(src, hsv, COLOR_BGR2HSV);  
        dst.create(hsv.size(), hsv.depth());
        //分离Hue/色相通道
        int ch[] = {0, 0};
        mixChannels(&hsv, 1, &dst, 1, ch, 1);
        imshow("H channel", dst);
        //分离Saturation/饱和度通道
        int ch1[] = {1, 0};
        mixChannels(&hsv, 1, &dst, 1, ch1, 1);
        imshow("S channel", dst);
        //分离Value/色调通道
        int ch2[] = {2, 0};
        mixChannels(&hsv, 1, &dst, 1, ch2, 1);
        imshow("V channel", dst);
     
        waitKey(0);
        return 0;
    }
    2、approxPolyDP 多边拟合函数
    approxPolyDP 主要功能是把一个连续光滑曲线折线化,对图像轮廓点进行多边形拟合。

    原理图:对比之前黑点连线,之后蓝色连线:

    参数详解;

    void approxPolyDP(
    InputArray curve,        //一般是由图像的轮廓点组成的点集
    OutputArray approxCurve, //表示输出的多边形点集
    double epsilon,          //主要表示输出的精度,就是另个轮廓点之间最大距离数,5,6,7,,8,,,,,
    bool closed              //表示输出的多边形是否封闭
    )
    示例: 

    #include <opencv2/opencv.hpp>    
    #include <stdio.h>    
    #include <stdlib.h>    
    #include <iostream>  
     
     
    using namespace cv;  
    using namespace std;  
     
     
    int main(int argc, char** argv)  
    {  
        Mat img = imread("4.jpg", -1);
        pyrDown(img, img, Size(img.cols/2, img.rows/2), 4);
        imshow("img", img);imwrite("img.jpg", img);
     
        //通过canny算法找轮廓,这样 findcontours 的结果会好些
        Mat canny_out;
        Canny(img, canny_out, 45, 127, 3, false);
        imshow("canny_out", canny_out);imwrite("canny_out.jpg", canny_out);
     
        //寻找轮廓
        vector<vector<Point>> contours;
        vector<Vec4i> hierachy;
        findContours(canny_out, contours, hierachy, RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(-1,-1));
        drawContours(img, contours, -1, Scalar(0,0,255), 1, 8, hierachy);
        
        //定义圆形、方形、旋转矩形、椭圆的存储容器
        vector<vector<Point>> contours_ploy(contours.size());
        vector<Rect> rects_ploy(contours.size());
        vector<Point2f> circle_centers(contours.size());
        vector<float> circle_radius(contours.size());
        vector<RotatedRect> RotatedRect_ploy;//注意:由于下面赋值的过程中有个点数大于5的条件,所以这里没有直接初始化,才有下面pushback的方法添加值。
        vector<RotatedRect> ellipse_ploy;//注意,这里是画椭圆,但是容器类型是 RotatedRect
     
        //将结果放到各自的容器中
        for (size_t i = 0; i< contours.size(); i++)
        {
            approxPolyDP(contours[i], contours_ploy[i], 5, true);
            rects_ploy[i] = boundingRect(contours_ploy[i]);
            minEnclosingCircle(contours_ploy[i], circle_centers[i], circle_radius[i]);
     
            if (contours_ploy[i].size() >5)
            {
                RotatedRect temp1 = minAreaRect(contours_ploy[i]);
                RotatedRect_ploy.push_back(temp1);
     
                RotatedRect temp2 = fitEllipse(contours_ploy[i]);
                ellipse_ploy.push_back(temp2);
            }
        }
     
        //定义最终绘图的图片
        Mat draw_rect(img.size(), img.type(), Scalar::all(0)), 
            draw_rotateRect(img.size(), img.type(), Scalar::all(0)), 
            draw_circle(img.size(), img.type(), Scalar::all(0)), 
            draw_ellipse(img.size(), img.type(), Scalar::all(0));
     
        //绘图圆形、矩形
        RNG rng(12345);
        for (size_t i = 0; i<contours.size(); i++)
        {
            Scalar color = Scalar(rng.uniform(0,255), rng.uniform(0,255), rng.uniform(0,255));
            rectangle(draw_rect, rects_ploy[i], color, 1, 8);
            circle(draw_circle, circle_centers[i], circle_radius[i], color, 1, 8);
        }
        imshow("draw_rect", draw_rect);imwrite("draw_rect.jpg", draw_rect);
        imshow("draw_circle", draw_circle);imwrite("draw_circle.jpg", draw_circle);
     
        //绘图椭圆形、旋转矩形
        Point2f pot[4];
        for (size_t i = 0; i<ellipse_ploy.size(); i++)
        {
            Scalar color = Scalar(rng.uniform(0,255), rng.uniform(0,255), rng.uniform(0,255));
            ellipse(draw_ellipse, ellipse_ploy[i], color, 1, 8);
     
            RotatedRect_ploy[i].points(pot);
            for(int j=0; j<4; j++)
            {
                line(draw_rotateRect, pot[j], pot[(j+1)%4], color);
            }
        }
        imshow("draw_ellipse", draw_ellipse);imwrite("draw_ellipse.jpg", draw_ellipse);
        imshow("draw_rotateRect", draw_rotateRect);imwrite("draw_rotateRect.jpg", draw_rotateRect);
     
     
        waitKey();
        return 1;
    }  
    3、 多边形绘制polylines()
    参数详解:

    void cv::polylines  (   Mat &   img,  //作为画布的矩阵
            const Point *const *    pts,  //折线顶点数组
            const int *     npts,         //折线顶点个数
            int     ncontours,            //待绘制折线数
            bool    isClosed,             //是否是闭合折线(多边形)
            const Scalar &      color,    //折线的颜色
            int     thickness = 1,        //折线粗细
            int     lineType = LINE_8,    //线段类型
            int     shift = 0             //缩放比例(0是不缩放,4是1/4)
        )
    二、矩形检测实现源码
    本文矩形检测代码来自于(我爱计算机公众号):https://mp.weixin.qq.com/s/WV78mvRn-cYm11cL4l2ScA

    分享的开源代码地址:https://github.com/alyssaq/opencv

    其算法流程:

    1.中值滤波去噪;

    2.依次提取不同的颜色通道(BGR)检测矩形;

    3.对每一通道使用canny检测边缘或者使用多个阈值二值化;

    4.使用findContours函数查找轮廓;

    5.使用approxPolyDP函数去除多边形轮廓一些小的波折;

    6.找到同时满足面积较大和形状为凸的四边形;

    7.判断轮廓中两两邻接直线夹角余弦是否小于0.3(意味着角度在90度附近),是则此四边形为找到的矩形。

    该代码效果还是不错的!

    实现源码,仅依赖于OpenCV:

    // The "Square Detector" program.
    // It loads several images sequentially and tries to find squares in
    // each image
    //“矩形检测”程序。
    //它按顺序加载了几张图像,并试图找到正方形
     
    #include "opencv2/core/core.hpp"
    #include "opencv2/imgproc/imgproc.hpp"
    #include "opencv2/highgui/highgui.hpp"
     
    #include <iostream>
    #include <math.h>
    #include <string.h>
     
    using namespace cv;
    using namespace std;
     
    static void help()
    {
        cout <<
            "\nA program using pyramid scaling, Canny, contours, contour simpification and\n"
            "memory storage to find squares in a list of images\n"
            "Returns sequence of squares detected on the image.\n"
            "the sequence is stored in the specified memory storage\n"
            "Call:\n"
            "./squares\n"
            "Using OpenCV version %s\n" << CV_VERSION << "\n" << endl;
    }
     
     
    int thresh = 50, N = 5;
    const char* wndname = "Square Detection Demo";
     
    // helper function:
    // finds a cosine of angle between vectors
    // from pt0->pt1 and from pt0->pt2
    //辅助功能:
    //求出向量夹角的余弦
    //从pt0->pt1到pt0->pt2
    static double angle(Point pt1, Point pt2, Point pt0)
    {
        double dx1 = pt1.x - pt0.x;
        double dy1 = pt1.y - pt0.y;
        double dx2 = pt2.x - pt0.x;
        double dy2 = pt2.y - pt0.y;
        return (dx1*dx2 + dy1 * dy2) / sqrt((dx1*dx1 + dy1 * dy1)*(dx2*dx2 + dy2 * dy2) + 1e-10);
    }
     
    // returns sequence of squares detected on the image.
    // the sequence is stored in the specified memory storage
    //返回在图像上检测到的正方形序列。
    //序列存储在指定的内存中
    static void findSquares(const Mat& image, vector<vector<Point> >& squares)
    {
        squares.clear();
     
        //Mat pyr, timg, gray0(image.size(), CV_8U), gray;
        //down-scale and upscale the image to filter out the noise
        //按比例放大图像,滤除噪声
        //pyrDown(image, pyr, Size(image.cols/2, image.rows/2));
        //pyrUp(pyr, timg, image.size());
     
     
        // blur will enhance edge detection
        //中值滤波将增强边缘检测
        Mat timg(image);
        medianBlur(image, timg, 9);
        Mat gray0(timg.size(), CV_8U), gray;
     
        vector<vector<Point> > contours;
     
        // find squares in every color plane of the image
        //在图像的每个颜色平面上找到正方形
        for (int c = 0; c < 3; c++)
        {
            int ch[] = { c, 0 };
            mixChannels(&timg, 1, &gray0, 1, ch, 1);//将输入数组的指定通道复制到输出数组的指定通道
     
            // try several threshold levels
            //尝试几个阈值级别
            for (int l = 0; l < N; l++)
            {
                // hack: use Canny instead of zero threshold level.
                // Canny helps to catch squares with gradient shading
                // Canny帮助捕捉带有渐变阴影的正方形
                if (l == 0)
                {
                    // apply Canny. Take the upper threshold from slider
                    // and set the lower to 0 (which forces edges merging)
                    Canny(gray0, gray, 5, thresh, 5);
                    // dilate canny output to remove potential
                    // holes between edge segments
                    dilate(gray, gray, Mat(), Point(-1, -1));
                }
                else
                {
                    // apply threshold if l!=0:
                    // tgray(x,y) = gray(x,y) < (l+1)*255/N ? 255 : 0
                    gray = gray0 >= (l + 1) * 255 / N;
                }
     
                // find contours and store them all as a list
                findContours(gray, contours, RETR_LIST, CHAIN_APPROX_SIMPLE);
     
                vector<Point> approx;
     
                // test each contour
                for (size_t i = 0; i < contours.size(); i++)
                {
                    // approximate contour with accuracy proportional
                    // to the contour perimeter
                    //近似轮廓与精度成正比
                    //到轮廓周长
                    approxPolyDP(Mat(contours[i]), approx, arcLength(Mat(contours[i]), true)*0.02, true);
     
                    // square contours should have 4 vertices after approximation
                    // relatively large area (to filter out noisy contours)
                    // and be convex.
                    // Note: absolute value of an area is used because
                    // area may be positive or negative - in accordance with the
                    // contour orientation
                    if (approx.size() == 4 &&
                        fabs(contourArea(Mat(approx))) > 1000 &&
                        isContourConvex(Mat(approx)))  //凸性检测 检测一个曲线是不是凸的
                    {
                        double maxCosine = 0;
     
                        for (int j = 2; j < 5; j++)
                        {
                            // find the maximum cosine of the angle between joint edges
                            double cosine = fabs(angle(approx[j % 4], approx[j - 2], approx[j - 1]));
                            maxCosine = MAX(maxCosine, cosine);
                        }
     
                        // if cosines of all angles are small
                        // (all angles are ~90 degree) then write quandrange
                        // vertices to resultant sequence
                        if (maxCosine < 0.3)
                            squares.push_back(approx);
                    }
                }
            }
        }
    }
     
     
    // the function draws all the squares in the image
    static void drawSquares(Mat& image, const vector<vector<Point> >& squares)
    {
        for (size_t i = 0; i < squares.size(); i++)
        {
            const Point* p = &squares[i][0];
     
            int n = (int)squares[i].size();
            //dont detect the border
            if (p->x > 3 && p->y > 3)
                polylines(image, &p, &n, 1, true, Scalar(0, 0, 255), 3, LINE_AA);
        }
        imshow(wndname, image);
    }
     
     
    int main(int /*argc*/, char** /*argv*/)
    {
        static const char* names[] = { "./image/2stickies.jpg", "./image/manyStickies.jpg",0 };
        help();
        namedWindow(wndname, 1);
        vector<vector<Point> > squares;
     
        for (int i = 0; names[i] != 0; i++)
        {
            Mat image = imread(names[i], 1);
            if (image.empty())
            {
                cout << "Couldn't load " << names[i] << endl;
                continue;
            }
     
            findSquares(image, squares);
            drawSquares(image, squares);
            imwrite( "out.jpg", image );
            int c = waitKey();
            if ((char)c == 27)
                break;
        }
        return 0;
    }

     

    前言
    1.OpenCV没有内置的矩形检测的函数,如果想检测矩形,要自己去实现。
    2.我这里使用的OpenCV版本是3.30.

    矩形检测
    1.得到原始图像之后,代码处理的步骤是:
    (1)滤波增强边缘。
    (2)分离图像通道,并检测边缘。
    (3) 提取轮廓。
    (4)使用图像轮廓点进行多边形拟合。
    (5)计算轮廓面积并得到矩形4个顶点。
    (6)求轮廓边缘之间角度的最大余弦。
    (7)画出矩形。
    2.代码

    //检测矩形
    //第一个参数是传入的原始图像,第二是输出的图像。
    void findSquares(const Mat& image,Mat &out)
    {
        int thresh = 50, N = 5;
        vector<vector<Point> > squares;
        squares.clear();

        Mat src,dst, gray_one, gray;

        src = image.clone();
        out = image.clone();
        gray_one = Mat(src.size(), CV_8U);
        //滤波增强边缘检测
        medianBlur(src, dst, 9);
        //bilateralFilter(src, dst, 25, 25 * 2, 35);

        vector<vector<Point> > contours;
        vector<Vec4i> hierarchy;

        //在图像的每个颜色通道中查找矩形
        for (int c = 0; c < image.channels(); c++)
        {
            int ch[] = { c, 0 };

            //通道分离
            mixChannels(&dst, 1, &gray_one, 1, ch, 1);

            // 尝试几个阈值
            for (int l = 0; l < N; l++)
            {
                // 用canny()提取边缘
                if (l == 0)
                {
                    //检测边缘
                    Canny(gray_one, gray, 5, thresh, 5);
                    //膨脹
                    dilate(gray, gray, Mat(), Point(-1, -1));
                    imshow("dilate", gray);
                }
                else
                {
                    gray = gray_one >= (l + 1) * 255 / N;
                }

                // 轮廓查找
                //findContours(gray, contours, RETR_CCOMP, CHAIN_APPROX_SIMPLE);
                findContours(gray, contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_SIMPLE);

                vector<Point> approx;
                
                // 检测所找到的轮廓
                for (size_t i = 0; i < contours.size(); i++)
                {
                    //使用图像轮廓点进行多边形拟合
                    approxPolyDP(Mat(contours[i]), approx, arcLength(Mat(contours[i]), true)*0.02, true);

                    //计算轮廓面积后,得到矩形4个顶点
                    if (approx.size() == 4 &&fabs(contourArea(Mat(approx))) > 1000 &&isContourConvex(Mat(approx)))
                    {
                        double maxCosine = 0;

                        for (int j = 2; j < 5; j++)
                        {
                            // 求轮廓边缘之间角度的最大余弦
                            double cosine = fabs(angle(approx[j % 4], approx[j - 2], approx[j - 1]));
                            maxCosine = MAX(maxCosine, cosine);
                        }

                        if (maxCosine < 0.3)
                        {
                            squares.push_back(approx);
                        }
                    }
                }
            }
        }

        
        for (size_t i = 0; i < squares.size(); i++)
        {
            const Point* p = &squares[i][0];

            int n = (int)squares[i].size();
            if (p->x > 3 && p->y > 3)
            {
                polylines(out, &p, &n, 1, true, Scalar(0, 255, 0), 3, LINE_AA);
            }
        }
        imshow("dst",out);
    }

    static double angle(Point pt1, Point pt2, Point pt0)
    {
        double dx1 = pt1.x - pt0.x;
        double dy1 = pt1.y - pt0.y;
        double dx2 = pt2.x - pt0.x;
        double dy2 = pt2.y - pt0.y;
        return (dx1*dx2 + dy1*dy2) / sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);
    }

    3.运行结果

    ————————————————
    版权声明:本文为CSDN博主「知来者逆」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/matt45m/article/details/95753563

    展开全文
  • 深度学习有没有检测矩形图片的方法,以LInkNet等为例,将图片裁成小图时有矩形图片产生,输入到模型中会报错,一般的模型都是正方形</p>
  • OpenCV检测矩形

    千次阅读 2019-04-22 12:52:44
    代码来自www.opencvchina.com #ifdef _CH_ #pragma package <opencv> #endif #ifndef _EiC #include "cv.h" #include "highgui.h" #include <stdio.h> #include <...string.h&g...

    代码来自www.opencvchina.com 

    #ifdef _CH_
    #pragma package <opencv>
    #endif
    
    #ifndef _EiC
    #include "cv.h"
    #include "highgui.h"
    #include <stdio.h>
    #include <math.h>
    #include <string.h>
    #endif
    
    int thresh = 50;
    IplImage* img = 0;
    IplImage* img0 = 0;
    CvMemStorage* storage = 0;
    CvPoint pt[4];
    const char* wndname = "Square Detection Demo";
    
    // helper function:
    // finds a cosine of angle between vectors
    // from pt0->pt1 and from pt0->pt2 
    double angle( CvPoint* pt1, CvPoint* pt2, CvPoint* pt0 )
    {
        double dx1 = pt1->x - pt0->x;
        double dy1 = pt1->y - pt0->y;
        double dx2 = pt2->x - pt0->x;
        double dy2 = pt2->y - pt0->y;
        return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);
    }
    
    // returns sequence of squares detected on the image.
    // the sequence is stored in the specified memory storage
    CvSeq* findSquares4( IplImage* img, CvMemStorage* storage )
    {
        CvSeq* contours;
        int i, c, l, N = 11;
        CvSize sz = cvSize( img->width & -2, img->height & -2 );
        IplImage* timg = cvCloneImage( img ); // make a copy of input image
        IplImage* gray = cvCreateImage( sz, 8, 1 ); 
        IplImage* pyr = cvCreateImage( cvSize(sz.width/2, sz.height/2), 8, 3 );
        IplImage* tgray;
        CvSeq* result;
        double s, t;
        // create empty sequence that will contain points -
        // 4 points per square (the square's vertices)
        CvSeq* squares = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvPoint), storage );
        
        // select the maximum ROI in the image
        // with the width and height divisible by 2
        cvSetImageROI( timg, cvRect( 0, 0, sz.width, sz.height ));
        
        // down-scale and upscale the image to filter out the noise
        cvPyrDown( timg, pyr, 7 );
        cvPyrUp( pyr, timg, 7 );
        tgray = cvCreateImage( sz, 8, 1 );
        
        // find squares in every color plane of the image
        for( c = 0; c < 3; c++ )
        {
            // extract the c-th color plane
            cvSetImageCOI( timg, c+1 );
            cvCopy( timg, tgray, 0 );
            
            // try several threshold levels
            for( l = 0; l < N; l++ )
            {
                // hack: use Canny instead of zero threshold level.
                // Canny helps to catch squares with gradient shading   
                if( l == 0 )
                {
                    // apply Canny. Take the upper threshold from slider
                    // and set the lower to 0 (which forces edges merging) 
                    cvCanny( tgray, gray, 0, thresh, 5 );
                    // dilate canny output to remove potential
                    // holes between edge segments 
                    cvDilate( gray, gray, 0, 1 );
                }
                else
                {
                    // apply threshold if l!=0:
                    //     tgray(x,y) = gray(x,y) < (l+1)*255/N ? 255 : 0
                    cvThreshold( tgray, gray, (l+1)*255/N, 255, CV_THRESH_BINARY );
                }
                
                // find contours and store them all as a list
                cvFindContours( gray, storage, &contours, sizeof(CvContour),
                    CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0) );
                
                // test each contour
                while( contours )
                {
                    // approximate contour with accuracy proportional
                    // to the contour perimeter
                    result = cvApproxPoly( contours, sizeof(CvContour), storage,
                        CV_POLY_APPROX_DP, cvContourPerimeter(contours)*0.02, 0 );
                    // square contours should have 4 vertices after approximation
                    // relatively large area (to filter out noisy contours)
                    // and be convex.
                    // Note: absolute value of an area is used because
                    // area may be positive or negative - in accordance with the
                    // contour orientation
                    if( result->total == 4 &&
                        fabs(cvContourArea(result,CV_WHOLE_SEQ)) > 1000 &&
                        cvCheckContourConvexity(result) )
                    {
                        s = 0;
                        
                        for( i = 0; i < 5; i++ )
                        {
                            // find minimum angle between joint
                            // edges (maximum of cosine)
                            if( i >= 2 )
                            {
                                t = fabs(angle(
                                (CvPoint*)cvGetSeqElem( result, i ),
                                (CvPoint*)cvGetSeqElem( result, i-2 ),
                                (CvPoint*)cvGetSeqElem( result, i-1 )));
                                s = s > t ? s : t;
                            }
                        }
                        
                        // if cosines of all angles are small
                        // (all angles are ~90 degree) then write quandrange
                        // vertices to resultant sequence 
                        if( s < 0.3 )
                            for( i = 0; i < 4; i++ )
                                cvSeqPush( squares,
                                    (CvPoint*)cvGetSeqElem( result, i ));
                    }
                    
                    // take the next contour
                    contours = contours->h_next;
                }
            }
        }
        
        // release all the temporary images
        cvReleaseImage( &gray );
        cvReleaseImage( &pyr );
        cvReleaseImage( &tgray );
        cvReleaseImage( &timg );
        
        return squares;
    }
    
    
    // the function draws all the squares in the image
    void drawSquares( IplImage* img, CvSeq* squares )
    {
        CvSeqReader reader;
        IplImage* cpy = cvCloneImage( img );
        int i;
        
        // initialize reader of the sequence
        cvStartReadSeq( squares, &reader, 0 );
        
        // read 4 sequence elements at a time (all vertices of a square)
        for( i = 0; i < squares->total; i += 4 )
        {
            CvPoint* rect = pt;
            int count = 4;
            
            // read 4 vertices
            memcpy( pt, reader.ptr, squares->elem_size );
            CV_NEXT_SEQ_ELEM( squares->elem_size, reader );
            memcpy( pt + 1, reader.ptr, squares->elem_size );
            CV_NEXT_SEQ_ELEM( squares->elem_size, reader );
            memcpy( pt + 2, reader.ptr, squares->elem_size );
            CV_NEXT_SEQ_ELEM( squares->elem_size, reader );
            memcpy( pt + 3, reader.ptr, squares->elem_size );
            CV_NEXT_SEQ_ELEM( squares->elem_size, reader );
            
            // draw the square as a closed polyline 
            cvPolyLine( cpy, &rect, &count, 1, 1, CV_RGB(0,255,0), 3, CV_AA, 0 );
        }
        
        // show the resultant image
        cvShowImage( wndname, cpy );
        cvReleaseImage( &cpy );
    }
    
    
    void on_trackbar( int a )
    {
        if( img )
            drawSquares( img, findSquares4( img, storage ) );
    }
    
    char* names[] = { "pic1.png", "pic2.png", "pic3.png",
                      "pic4.png", "pic5.png", "pic6.png", 0 };
    
    int main(int argc, char** argv)
    {
        int i, c;
        // create memory storage that will contain all the dynamic data
        storage = cvCreateMemStorage(0);
    
        for( i = 0; names != 0; i++ )
        {
            // load i-th image
            img0 = cvLoadImage( names, 1 );
            if( !img0 )
            {
                printf("Couldn't load %s\n", names );
                continue;
            }
            img = cvCloneImage( img0 );
            
            // create window and a trackbar (slider) with parent "image" and set callback
            // (the slider regulates upper threshold, passed to Canny edge detector) 
            cvNamedWindow( wndname, 1 );
            cvCreateTrackbar( "canny thresh", wndname, &thresh, 1000, on_trackbar );
            
            // force the image processing
            on_trackbar(0);
            // wait for key.
            // Also the function cvWaitKey takes care of event processing
            c = cvWaitKey(0);
            // release both images
            cvReleaseImage( &img );
            cvReleaseImage( &img0 );
            // clear memory storage - reset free space position
            cvClearMemStorage( storage );
            if( c == 27 )
                break;
        }
        
        cvDestroyWindow( wndname );
        
        return 0;
    }
    
    #ifdef _EiC
    main(1,"squares.c");
    #endif

     

    展开全文
  • MATLAB识别二值图像,对兴趣区域进行矩形标注,主要针对彩图转二值图像后有明显边界的图片。
  • 检测一个矩形是否与另一个矩形相交。 var intersects = require ( 'intersects' ) ; intersects ( rect1 , rect2 , tolerance ) ; rect1和rect2是矩形: { top, left, bottom, right, width, height } 。 公差:...
  • 用c#的GDI+绘图实现一个简单的飞机游戏来演示矩形碰撞和像素碰撞的效果,主角飞机方向移动和敌机碰撞,没写发射子弹之类的功能。
  • 实习时候遇到的一个任务 检测手机存在 区分人脸是真人还是假人 鲁棒性不太高 里面夹杂了人脸检测 不需要人脸的检测的 可以把人脸检测那部分代码直接去掉就能用了
  • cocos2d-x 检测矩形碰撞

    2017-01-06 02:00:12
    今天学习研究cocos2d-x的碰撞检测发现 升级到2.x之后发现 CCRect::CCRectIntersectsRect 方法已经被废弃 同时提供了bool intersectsRect(const CCRect& rect) const;方法将其取代如下: ...//碰撞检测矩形碰撞 

    今天学习研究cocos2d-x的碰撞检测发现 升级到2.x之后发现 CCRect::CCRectIntersectsRect 方法已经被废弃 同时提供了bool intersectsRect(const CCRect& rect) const;方法将其取代如下:

    1. //碰撞检测,矩形碰撞    
    2. if((sprite1->boundingBox()).intersectsRect(sprite2->boundingBox()))    
    3. {    
    4.     label->setString("碰撞啦");    
    5. }else    
    6. {    
    7.     label->setString("还是没有碰撞");    
    8. }    
    PS:

    在cocos2d-x 的2.0.4 版本中,CCRectEqualToRect 、CCRectContainsPoint、CCRectIntersectsRect已不再推荐使用,取而代之的是 equals、containsPoint、intersectsRect。

    equals、containsPoint、intersectsRect,这三个方法在 CCRect 中定义如下:
        bool equals(const CCRect& rect) const;   
        bool containsPoint(const CCPoint& point) const;
        bool intersectsRect(const CCRect& rect) const;
    使用方法类似:
       sprite->boundingBox().containsPoint(point);

    展开全文
  • CCF NOI 1048.检测矩形

    2018-01-11 18:40:59
    你的任务就是检测矩阵是否符合条件,或者在仅改变一个矩阵元素的情况下能否符合条件。 “改变矩阵元素”的操作定义为0变成1或者1变成0。 输入 输入n + 1行,第1行为矩阵的大小n(0 输出 如果矩阵符合...
  • 可以检测空心和实心的矩形和菱形 #include "cv.h" #include "highgui.h" #include <stdio.h> #include <math.h> #include <string.h> #include "opencv2/imgproc.hpp" //////////////...
  • # -*- coding: utf-8 -*- """ Created on Thu Sep 19 14:51:00 2019 @author: Andrea """ import os import numpy as np import codecs import json from glob import glob import cv2 ...from sklearn...
  • OPENCV检测矩形并计算其中心

    千次阅读 2014-10-27 18:28:46
    const char * wndname = "正方形检测 demo";   //angle函数用来返回(两个向量之间找到角度的余弦值) double angle( CvPoint* pt1, CvPoint* pt2, CvPoint* pt0 ) {  double dx1 = pt1->x - pt0->x...
  • import json import cv2 import os # json文件路径 path = r"complex_train.json" file = open(path, "r", encoding='utf-8') fileJson = json.load(file) field = fileJson["annotations"] # 图片路径 ...
  • import cv2 from PIL import Image import torchvision.transforms.functional as FT import random def find_intersection(set_1, set_2): """ Find the intersection of every box combination between ...
  • [img=http://img.my.csdn.net/uploads/201208/14/1344934684_6957.gif][/img] 主要用到了这几个API DrawFocusRect InvertRect Rectangle PtInRect SetCapture ReleaseCapture ...具体代码看下面:
  • 1.OpenCV没有内置的矩形检测的函数,如果想检测矩形,要自己去实现。 2.我这里使用的OpenCV版本是3.30. 矩形检测 1.得到原始图像之后,代码处理的步骤是: (1)滤波增强边缘。 (2)分离图像通道,并检测边缘。 (3...
  • 检测直线,圆形,矩形

    2013-09-24 16:01:49
    检测直线:cvHoughLines,cvHoughLines2 检测圆:cvHoughCircles 检测矩形:opencv中没有对应的函数,下面有段代码可以检测矩形,是通过先找直线,然后找到直线平行与垂直的四根线。
  • 矩形检测OPENCV

    2019-03-31 22:00:30
    矩形检测,采用OPENCV开发,通过轮廓获得矩形,效果比较好
  • C++ - OpenCV矩形检测

    千次阅读 2019-01-03 11:42:29
    一个非常熟悉的例子是 拍摄的文本的预处理。 将文档定位出矩形,然后透视变换校正,方便...2.依次提取不同的颜色通道(BGR)检测矩形; 3.对每一通道使用canny检测边缘或者使用多个阈值二值化; 4.使用findConto...
  • QT矩形检测

    2017-08-16 15:24:46
    QT矩形检测 ,基于opencv,带opencv完整,直接可以编译运行

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,193
精华内容 1,277
关键字:

检测矩形