OpenCV 圆与矩形识别的方法

最近一个项目用到了图像识别,之前从未接触过OpenCV,经过各种找教程,终于是搞懂了一些。

整个具体流程大概是获取图像-->图像二值化,灰度图(cvtColor)-->图像降噪(GaussianBlur)->轮廓识别(cvFindContours)-->形状判断。

大多数教程很专业,各种参数分析看不懂,经过各种搜索终于是搞懂了。

识别圆

在识别圆方面,OpenCV有内置的方法:霍夫圆变化:

HoughCircles(edges, circles, CV_HOUGH_GRADIENT, 1.5, 10, 200, 100, 0, 0);

参数分析:

edges:灰度图像

circles: std::vector<Vec3f> circles;数组,用来存储圆的坐标信息

CV_HOUGH_GRADIENT:Hough 变换方式,目前只支持CV_HOUGH_GRADIENT, which is basically 21HT, described in [Yuen03].默认用这个

1.5:累加器图像的分辨率,1的时候是与获取到的图像相同,1.5就是1.5倍

10:圆与圆的最小距离,两个圆心距离如果在范围内则被认定为1个圆

200:100-200两个参数选就够了

100:默认100,数值越低识别圆越不精确(圆的数量识别变多可能有个弧线就被识别是圆)

最后两个参数分别是识别 圆的最小,最大的面积。

矩形识别

矩形识别并没有内置方法,需要自己手写。

最主要的方法是二值化。通过二值化来调节识别的强度。

cvThreshold(tgray, gray, 75, 250, CV_THRESH_BINARY);

参数分析:

src:原始数组 (单通道 , 8-bit of 32-bit 浮点数)。

dst:输出数组,必须与 src 的类型一致,或者为 8-bit。

threshold:阈值

max_value:使用 CV_THRESH_BINARY 和 CV_THRESH_BINARY_INV 的最大值。

threshold_type:阈值类型

threshold_type=CV_THRESH_BINARY:如果 src(x,y)>threshold ,dst(x,y) = max_value; 否则,dst(x,y)=0;

threshold_type=CV_THRESH_BINARY_INV:如果 src(x,y)>threshold,dst(x,y) = 0; 否则,dst(x,y) = max_value.

threshold_type=CV_THRESH_TRUNC:如果 src(x,y)>threshold,dst(x,y) = max_value; 否则dst(x,y) = src(x,y).

threshold_type=CV_THRESH_TOZERO:如果src(x,y)>threshold,dst(x,y) = src(x,y) ; 否则 dst(x,y) = 0。

threshold_type=CV_THRESH_TOZERO_INV:如果 src(x,y)>threshold,dst(x,y) = 0 ; 否则dst(x,y) = src(x,y).

效果图如下:

在矩形识别里面的二值化图:

圆识别:

源码:

#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <WINSOCK2.H>
#include<iostream>
#include<thread>
#include <winsock2.h>
#include <stdio.h>
#include<string>
#include <windows.h>
#pragma comment(lib,"ws2_32.lib")
#include<vector>

using namespace cv;

   //////////////////////////////////////////////////////////////////
   //函数功能:用向量来做COSα=两向量之积/两向量模的乘积求两条线段夹角
   //输入:  线段3个点坐标pt1,pt2,pt0,最后一个参数为公共点
   //输出:  线段夹角,单位为角度
   //////////////////////////////////////////////////////////////////
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;
 double angle_line = (dx1*dx2 + dy1 * dy2) / sqrt((dx1*dx1 + dy1 * dy1)*(dx2*dx2 + dy2 * dy2) + 1e-10);//余弦值
 return acos(angle_line) * 180 / 3.141592653;
}
//////////////////////////////////////////////////////////////////
//函数功能:采用多边形检测,通过约束条件寻找矩形
//输入:  img 原图像
//     storage 存储
//     minarea,maxarea 检测矩形的最小/最大面积
//     minangle,maxangle 检测矩形边夹角范围,单位为角度
//输出:  矩形序列
//////////////////////////////////////////////////////////////////
CvSeq* findSquares4(IplImage* img, CvMemStorage* storage, int minarea, int maxarea, int minangle, int maxangle, int(&temp)[30])
{
 CvSeq* contours;//边缘
 int N = 6; //阈值分级
 CvSize sz = cvSize(img->width & -2, img->height & -2);
 IplImage* timg = cvCloneImage(img);//拷贝一次img
 IplImage* gray = cvCreateImage(sz, 8, 1); //img灰度图
 IplImage* pyr = cvCreateImage(cvSize(sz.width / 2, sz.height / 2), 8, 3); //金字塔滤波3通道图像中间变量
 IplImage* tgray = cvCreateImage(sz, 8, 1); ;
 CvSeq* result;
 double s, t;
 int sk = 0;
 CvSeq* squares = cvCreateSeq(0, sizeof(CvSeq), sizeof(CvPoint), storage);

 cvSetImageROI(timg, cvRect(0, 0, sz.width, sz.height));
 //金字塔滤波
 cvPyrDown(timg, pyr, 7);
 cvPyrUp(pyr, timg, 7);
 //在3个通道中寻找矩形
 for (int c = 0; c < 3; c++) //对3个通道分别进行处理
 {
 cvSetImageCOI(timg, c + 1);
 cvCopy(timg, tgray, 0); //依次将BGR通道送入tgray
 for (int l = 0; l < N; l++)
 {
  //不同阈值下二值化
  cvThreshold(tgray, gray, 75, 250, CV_THRESH_BINARY);
  cvShowImage("111", gray);
  cvFindContours(gray, storage, &contours, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0, 0));
  while (contours)
  { //多边形逼近
  result = cvApproxPoly(contours, sizeof(CvContour), storage, CV_POLY_APPROX_DP, cvContourPerimeter(contours)*0.02, 0);

  //如果是凸四边形并且面积在范围内
  if (result->total == 4 && fabs(cvContourArea(result, CV_WHOLE_SEQ)) > minarea && fabs(cvContourArea(result, CV_WHOLE_SEQ)) < maxarea && cvCheckContourConvexity(result))
  {

   s = 0;
   //判断每一条边
   for (int i = 0; i < 5; i++)
   {
   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;
   }
   }
   //这里的S为直角判定条件 单位为角度
   if (s > minangle && s < maxangle)
   {
   for (int i = 0; i < 4; i++)
    cvSeqPush(squares, (CvPoint*)cvGetSeqElem(result, i));
   CvRect rect = cvBoundingRect(contours, 1);    // 获取矩形边界框
   CvPoint p1;
   p1 = cvPoint(rect.x + rect.width / 2, rect.y + rect.height / 2);  //矩形中心坐标
   std::cout << "X:" << p1.x << "Y:" << p1.y << std::endl;
   }
  }
  contours = contours->h_next;
  }
 }
 std::cout << "圆的数量是"<<sk << std::endl;
 temp[26] = sk;

 sk = 0;
 }
 cvReleaseImage(&gray);
 cvReleaseImage(&pyr);
 cvReleaseImage(&tgray);
 cvReleaseImage(&timg);

 return squares;
}
//////////////////////////////////////////////////////////////////
//函数功能:画出所有矩形
//输入:  img 原图像
//     squares 矩形序列
//     wndname 窗口名称
//输出:  图像中标记矩形
//////////////////////////////////////////////////////////////////
void drawSquares(IplImage* img, CvSeq* squares, const char* wndname)
{
 CvSeqReader reader;
 IplImage* cpy = cvCloneImage(img);
 CvPoint pt[4];
 int i;
 cvStartReadSeq(squares, &reader, 0);
 for (i = 0; i < squares->total; i += 4)
 {
 CvPoint* rect = pt;
 int count = 4;
 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);
 //cvPolyLine( cpy, &rect, &count, 1, 1, CV_RGB(0,255,0), 3, CV_AA, 0 );
 cvPolyLine(cpy, &rect, &count, 1, 1, CV_RGB(rand() & 255, rand() & 255, rand() & 255), 1, CV_AA, 0);//彩色绘制
 }
 cvShowImage("22", cpy);
 cvReleaseImage(&cpy);
}

void SendMessageOne()
{
 //开起摄像头
 VideoCapture capture;
 capture.open(0);
 Mat edges; //定义转化的灰度图
 if (!capture.isOpened())
 namedWindow("【效果图】", CV_WINDOW_NORMAL);
 const char* winn = "1111";
 if (!capture.isOpened())
 //namedWindow(winn, CV_WINDOW_NORMAL);
 CvMemStorage* storage = 0;
 CvMemStorage* storage = 0;
 storage = cvCreateMemStorage(0);
 while (1)
 {
 int Y=0, J=0;
 Mat frame;
 capture >> frame;
 IplImage img0 = frame;
 //drawSquares(&img0, findSquares4(&img0, storage, 100, 2000, 80, 100, a), winn);
 //cvClearMemStorage(storage); //清空存储
 Mat E = frame(Range(1, 320), Range(1, 240));
 cvtColor(frame, edges, CV_BGR2GRAY);
 //高斯滤波
 GaussianBlur(edges, edges, Size(7, 7), 2, 2);
 std::vector<Vec3f> circles;//存储每个圆的位置信息
      //霍夫圆
 HoughCircles(edges, circles, CV_HOUGH_GRADIENT, 1.5, 10, 100, 100, 0, 50);
 for (size_t i = 0; i < circles.size(); i++)
 {
  Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
  int radius = cvRound(circles[i][2]);
  //std::cout << "圆的X是" << circles[i][0] << "圆的Y是" << circles[i][1] << std:: endl;
  //绘制圆轮廓
  circle(frame, center, radius, Scalar(155, 50, 255), 3, 8, 0);
  int R = frame.at<Vec3b>(cvRound(circles[i][1]), cvRound(circles[i][0]))[2];//R
  int G = frame.at<Vec3b>(cvRound(circles[i][1]), cvRound(circles[i][0]))[1];//G
  int B = frame.at<Vec3b>(cvRound(circles[i][1]), cvRound(circles[i][0]))[0];//B
  int num = R + G + B;
  std::cout << "圆心颜色是" << num << std::endl;
        }

 imshow("【效果图】", frame);
 waitKey(30);
 }
}

int main()
{
 std::thread *a = new std::thread(SendMessageOne);
 a->join();

 return 0;
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • python+opencv识别图片中的圆形

    本文实例为大家分享了python+opencv识别图片中足球的方法,供大家参考,具体内容如下 先补充下霍夫圆变换的几个参数知识: dp,用来检测圆心的累加器图像的分辨率于输入图像之比的倒数,且此参数允许创建一个比输入图像分辨率低的累加器.上述文字不好理解的话,来看例子吧.例如,如果dp= 1时,累加器和输入图像具有相同的分辨率.如果dp=2,累加器便有输入图像一半那么大的宽度和高度. minDist,为霍夫变换检测到的圆的圆心之间的最小距离,即让我们的算法能明显区分的两个不同圆之间的最小距离.这

  • OpenCV 圆与矩形识别的方法

    最近一个项目用到了图像识别,之前从未接触过OpenCV,经过各种找教程,终于是搞懂了一些. 整个具体流程大概是获取图像-->图像二值化,灰度图(cvtColor)-->图像降噪(GaussianBlur)->轮廓识别(cvFindContours)-->形状判断. 大多数教程很专业,各种参数分析看不懂,经过各种搜索终于是搞懂了. 识别圆 在识别圆方面,OpenCV有内置的方法:霍夫圆变化: HoughCircles(edges, circles, CV_HOUGH_GRADIENT

  • Python+OpenCV实现信用卡数字识别的方法详解

    目录 一.模板图像处理 二.信用卡图片预处理 一.模板图像处理 (1)灰度图.二值图转化 template = cv2.imread('C:/Users/bwy/Desktop/number.png') template_gray = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY) cv_show('template_gray', template_gray) # 形成二值图像,因为要做轮廓检测 ret, template_thresh = cv2.thre

  • OpenCV实现去除背景识别的方法总结

    目录 实现效果 实现代码 补充 实现效果 效果如图,只识别一定距离内的物体 哈哈哈哈哈哈哈哈哈,但我不知道这有什么用 实现代码 import pyrealsense2 as rs import numpy as np import cv2 # 排除背景色 WIDTH = 848 HEIGHT = 480 # 初始化 config = rs.config() config.enable_stream(rs.stream.color, WIDTH, HEIGHT, rs.format.bgr8, 3

  • Dlib+OpenCV深度学习人脸识别的方法示例

    前言 人脸识别在LWF(Labeled Faces in the Wild)数据集上人脸识别率现在已经99.7%以上,这个识别率确实非常高了,但是真实的环境中的准确率有多少呢?我没有这方面的数据,但是可以确信的是真实环境中的识别率并没有那么乐观.现在虽然有一些商业应用如员工人脸识别管理系统.海关身份验证系统.甚至是银行人脸识别功能,但是我们可以仔细想想员工人脸识别管理,海关身份证系统的应用场景对身份的验证功能其实并没有商家吹嘘的那么重要,打个比方说员工上班的时候刷脸如果失败了会怎样,是不是重新识

  • OpenCV绘制圆端矩形的示例代码

    目录 功能函数 测试代码 测试效果 本文主要介绍了OpenCV绘制圆端矩形的示例代码,分享给大家,具体如下: 功能函数 // 绘制圆端矩形(药丸状,pill) void DrawPill(cv::Mat mask, const cv::RotatedRect &rotatedrect, const cv::Scalar &color, int thickness, int lineType) { cv::Mat canvas = cv::Mat::zeros(mask.size(), CV

  • Python OpenCV招商银行信用卡卡号识别的方法

    学在前面 从本篇博客起,我们将实际完成几个小案例,第一个就是银行卡号识别,预计本案例将写 5 篇左右的博客才可以完成,一起加油吧. 本文的目标是最终获取一套招商银行卡,0~9 数字的图,对于下图的数字,我们需要提取出来,便于后续模板匹配使用.不过下图中找到的数字不完整,需要找到尽量多的卡片,然后补齐这些数字. 提取卡片相关数字 先对上文中卡片中的数字进行相关提取操作,加载图片的灰度图,获取目标区域.在画板中模拟一下坐标区域,为了便于进行后续的操作. 具体代码如下: import cv2 as c

  • python 用opencv调用训练好的模型进行识别的方法

    此程序为先调用opencv自带的人脸检测模型,检测到人脸后,再调用我自己训练好的模型去识别人脸,使用时更改模型地址即可 #!usr/bin/env python import cv2 font=cv2.FONT_HERSHEY_SIMPLEX cascade1 = cv2.CascadeClassifier("D:\\opencv249\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt_tree.xml"

  • 使用c++实现OpenCV绘制圆端矩形

    功能函数 // 绘制圆端矩形(药丸状,pill) void DrawPill(cv::Mat mask, const cv::RotatedRect &rotatedrect, const cv::Scalar &color, int thickness, int lineType) { cv::Mat canvas = cv::Mat::zeros(mask.size(), CV_8UC1); // 确定短边,短边绘制圆形 cv::RotatedRect rect = rotatedre

  • OpenCV绘制圆角矩形的方法实例

    功能函数 // 绘制圆角矩形 void DrawRotatedRectChamfer(cv::Mat mask,const cv::RotatedRect rotatedrect, float radius,const cv::Scalar &color, int thickness, int lineType) { // 创建画布 cv::Mat canvas = cv::Mat::zeros(mask.size(), CV_8UC1); cv::RotatedRect newrotatedr

  • python+opencv实现动态物体识别

    注意:这种方法十分受光线变化影响 自己在家拿着手机瞎晃的成果图: 源代码: # -*- coding: utf-8 -*- """ Created on Wed Sep 27 15:47:54 2017 @author: tina """ import cv2 import numpy as np camera = cv2.VideoCapture(0) # 参数0表示第一个摄像头 # 判断视频是否打开 if (camera.isOpened()

随机推荐