利用opencv检测出矩形

利用opencv和c++语言来检测出矩形轮廓并且返回矩形的顶点坐标

#pragma once
#include "TROOT.h"
#include "CBinToProfile.h"
#include "TH1.h"
#include "CBmpDiff.h"
#include "CCircleToPeak.h"
#include "CColorCut.h"
#include "CCubicBSpline.h"
#include "CCurveAngle.h"
#include "CEdgeHit.h"
#include "CEdgeHitChain.h"
#include "CEdgeToCircleChain.h"
#include "CEdgeToFloat.h"
#include "CFloatMatch.h"
#include "CFrame.h"
#include "CIntProfileToFloat.h"
#include "CLBP.h"
#include "CLine.h"
#include "CLinePara.h"
#include "CNormToPeak.h"
#include "CPicToBin.h"
#include "CPicToEdge.h"
#include "CPointProjection.h"
#include "CPointToCircle.h"
#include "CPointToNorm.h"
#include "CPointToPeak.h"
#include "CProfile.h"
#include "CRegionMatch.h"
#include "CSixSword.h"
#include "CTime.h"
#include "lib.h"
#include "vlib.h"
#include "paras.h"
#include "spline.h"
#include <opencv2/opencv.hpp>
#include <iostream>
#include <windows.h>

using namespace cv;
using namespace std;

void setFrame(VideoCapture cap, double w, double h)
{
    cap.set(CV_CAP_PROP_FRAME_WIDTH, w);
    cap.set(CV_CAP_PROP_FRAME_HEIGHT, h);
}

CvMemStorage* storage;//CvMemStorage 动态内存存储及操作函数
CvMemStorage* tempStorage;
void initStorage()//初始化内存空间
{
    storage = cvCreateMemStorage(0);//分配内存空间
    tempStorage = cvCreateMemStorage(0);
}
void releaseStorage()//释放内存空间
{
    cvReleaseMemStorage (&storage);
    cvReleaseMemStorage (&tempStorage);
}

CvSeq* tempContour;
CvSeqWriter  writer;
CEdgeHit *tempHit;
CvPoint tempPoint;

CvSeq* transform(CEdgeHitChain chain)//自定义的transform函数
{
    tempContour = cvCreateSeq(CV_SEQ_POLYGON, sizeof(CvSeq), sizeof(CvPoint), tempStorage);//创建序列
    cvStartAppendToSeq( tempContour, &writer );//序列写入操作把temppoint写入tempContour

    tempHit = chain.first;
    while (tempHit!=chain.last)
    {
        tempPoint.x = tempHit->x;
        tempPoint.y = tempHit->y;
        CV_WRITE_SEQ_ELEM( tempPoint, writer );//通过循环把tempPoint全部写入writer
        tempHit = tempHit->next;
    }
    return tempContour;//返回轮廓
}

// angle函数用来返回(两个向量之间找到角度的余弦值)勾股定理
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);
}

int main(int argc, char *argv[])
{
    int c;
    printf("welcome!\n");
    VideoCapture cap_1;
    cap_1.open(0);
    if (!cap_1.isOpened())
    {
        printf("摄像头1打开失败!\n");
        return -1;
    }
    double w = 320, h = 320;
    setFrame(cap_1, w, h);

    Mat frame_1;
    IplImage* image_1;
    IplImage* gray;
    CvSize sz;
    CSixSword tc;

    CvSeq* contour;
    CvSeq* result;
    CvSeq* squares;

    initStorage();
    bool stop = false;
    while (!stop)
    {
        cout << "----------------------------------" << endl;
        cap_1 >> frame_1;
        GaussianBlur(frame_1, frame_1, cv::Size(5, 5), 0, 0);//高斯滤波
        image_1 = &IplImage(frame_1);
        //image_1 = cvLoadImage("pic.png", 1);
        //image_1 = cvLoadImage("ggu.jpg", 1);
        //image_1 = cvLoadImage("ppo.png", 1);

        sz = cvSize(image_1->width, image_1->height);
        gray = cvCreateImage(sz, IPL_DEPTH_8U, 1);//创建头并分配数据
        cvCvtColor(image_1, gray, CV_BGR2GRAY);//灰度处理
        tc.setup(gray);//把灰度图传给tc
        tc.transform();
        cout << "v.size:" << tc.v.size() << endl;

        contour = cvCreateSeq(CV_SEQ_POLYGON, sizeof(CvSeq), sizeof(CvPoint), storage);//创建序列contour
        squares = cvCreateSeq(0, sizeof(CvSeq), sizeof(CvPoint), storage);//创建序列squares

        double s, t;
        for(int i = 0; i < tc.v.size(); i++)
        {
            contour = transform(tc.v[i]);//返回轮廓
            result = cvApproxPoly(contour, sizeof(CvContour), storage, CV_POLY_APPROX_DP, cvContourPerimeter(contour)*0.02, 0);//逼近函数
            if (result->total == 4 && cvCheckContourConvexity(result))//检测是否是四边形和凸边形
            {
                s = 0;
                for (int j = 2; j < 5; j++)//for循环来判断四边形的顶点是否都是直角
                {
                    t = fabs(angle(
                        (CvPoint*)cvGetSeqElem(result, j),
                        (CvPoint*)cvGetSeqElem(result, j - 2),
                        (CvPoint*)cvGetSeqElem(result, j - 1)));
                    s = s > t ? s : t;
                }
                if (s < 0.1)
                    for (int j = 0; j < 4; j++)
                        cvSeqPush(squares, (CvPoint*)cvGetSeqElem(result, j));//squares最后存储的就是矩形
            }
        }

        cout << "squares->total:" << squares->total/4 << endl << endl;

        CvSeqReader reader;
        cvStartReadSeq(squares, &reader, 0);
        int i;
        int x[4] = { 0 }, y[4] = { 0 };
        for (i = 0; i < squares->total; i += 4)//i+=4是因为四个点才是一矩形
        {
            CvPoint pt[4], *rect = pt;
            int count = 4;
            CV_READ_SEQ_ELEM(pt[0], reader);//for循环来读取顶点坐标
            CV_READ_SEQ_ELEM(pt[1], reader);
            CV_READ_SEQ_ELEM(pt[2], reader);
            CV_READ_SEQ_ELEM(pt[3], reader);
            cout << "--------square>>" << i/4+1 << endl;
            for (int i = 0; i<4; i++)
            {
                x[i] = rect[i].x;
                y[i] = rect[i].y;
                cout << "x" << i << ":" << x[i] << '\t';
                cout << "y" << i << ":" << y[i] << endl;
            }
            cvPolyLine(image_1, &rect, &count, 1, 1, CV_RGB(0, 255, 0), 1, CV_AA, 0);//在图像中用绿色线标出矩形区域
        }
        cvShowImage("Vedio_1", image_1);//显示窗口
        if (waitKey(27) >= 0)//Esc键退出
            stop = true;
    }
    releaseStorage();//释放内存
    return 0;
}

代码中有导师写的类所以需要先把导师的类转换成逼近函数需要的数据类型就花费了很长时间,不过这个过程让自己对opencv更了解了~~棒棒的 导师的最终任务是完成双目程序 不过这个代码里有3个问题!
程序使用的样图
这个是运行后的图片你可以看到绿色的框框就是程序识别的矩形
这个是矩形坐标

1.在图片中我们能看到所返回的矩形坐标是有偏差的暂时还没有解决~~
2.检测矩形是会把外矩形也检测进去这个也仍未解决~~
3.程序运行时所占用的内存会一直上升,上升到一定值时程序就会报错中止~~

  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值