#include <iostream>
#include <vector>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace std;
using namespace cv;
int main()
{
// Read input binary image
Mat image= imread("./binaryGroup.bmp",0);
if (!image.data)
return 0;
namedWindow("Binary Image");
imshow("Binary Image",image);
// Get the contours of the connected components
vector<vector<Point>> contours;
//findContours的输入是二值图像
findContours(image,
contours, // a vector of contours
CV_RETR_EXTERNAL, // retrieve the external contours
CV_CHAIN_APPROX_NONE); // retrieve all pixels of each contours
// Print contours' length轮廓的个数
cout << "Contours: " << contours.size() << endl;
vector<vector<Point>>::const_iterator itContours= contours.begin();
for ( ; itContours!=contours.end(); ++itContours) {
cout << "Size: " << itContours->size() << endl;//每个轮廓包含的点数
}
// draw black contours on white image
Mat result(image.size(),CV_8U,Scalar(0));
drawContours(result,contours, //画出轮廓
-1, // draw all contours
Scalar(255), // in black
2); // with a thickness of 2
namedWindow("Contours");
imshow("Contours",result);
// Eliminate too short or too long contours
int cmin= 100; // minimum contour length
int cmax= 1000; // maximum contour length
vector<vector<Point>>::const_iterator itc= contours.begin();
while (itc!=contours.end()) {
if (itc->size() < cmin || itc->size() > cmax)
itc= contours.erase(itc);
else
++itc;
}
// draw contours on the original image
Mat original= imread("./group.bmp");
drawContours(original,contours,
-1, // draw all contours
Scalar(255,255,255), // in white
2); // with a thickness of 2
namedWindow("Contours on Animals");
imshow("Contours on Animals",original);
// Let's now draw black contours on white image
//result.setTo(Scalar(0));
//If the third parameter of this function is a negative value, then all contours are drawn.
//Otherwise, it is possible to specify the index of the contour to be drawn
drawContours(result,contours,
-1, // draw all contours
Scalar(255), // in black
1); // with a thickness of 1
image= imread("./binaryGroup.bmp",1);
// testing the bounding box
Rect r0= boundingRect(Mat(contours[0]));//boundingRect获取这个外接矩形
rectangle(result,r0,Scalar(255,255,255),2);
// testing the enclosing circle
float radius;
Point2f center;
minEnclosingCircle(Mat(contours[1]),center,radius);//对轮廓进行多变形逼近
circle(result,Point(center),static_cast<int>(radius),Scalar(255),2);
RotatedRect rrect= fitEllipse(Mat(contours[2]));
ellipse(result,rrect,Scalar(255),2);
//testing the approximate polygon
vector<Point> poly;
approxPolyDP(Mat(contours[2]),poly,5,true);
cout << "Polygon size: " << poly.size() << endl;
Iterate over each segment and draw it
vector<Point>::const_iterator itp= poly.begin();
while (itp!=(poly.end()-1)) {
line(result,*itp,*(itp+1),Scalar(255),2);
++itp;
}
// last point linked to first point
line(result,*(poly.begin()),*(poly.end()-1),Scalar(20),2);
// testing the convex hull
vector<Point> hull;
convexHull(Mat(contours[3]),hull);
// Iterate over each segment and draw it
vector<Point>::const_iterator it= hull.begin();
while (it!=(hull.end()-1)) {
line(result,*it,*(it+1),Scalar(255),2);
++it;
}
// last point linked to first point
line(result,*(hull.begin()),*(hull.end()-1),Scalar(255),2);
// testing the moments
//iterate over all contours
itc= contours.begin();
while (itc!=contours.end()) {
// compute all moments
Moments mom= moments(Mat(*itc++));
// draw mass center
circle(result,
// position of mass center converted to integer
Point(mom.m10/mom.m00,mom.m01/mom.m00),
2,Scalar(255),2); // draw black dot
}
namedWindow("Some Shape descriptors");
imshow("Some Shape descriptors",result);
// New call to findContours but with CV_RETR_LIST flag
image= imread("./binaryGroup.bmp",0);
// Get the contours of the connected components
findContours(image,
contours, // a vector of contours
CV_RETR_LIST, // retrieve the external and internal contours
CV_CHAIN_APPROX_NONE); // retrieve all pixels of each contours
// draw black contours on white image
result.setTo(Scalar(0));
drawContours(result,contours,
-1, // draw all contours
Scalar(255), // in black
2); // with a thickness of 2
namedWindow("All Contours");
imshow("All Contours",result);
waitKey();
return 0;
}
一、对于相对路径的读取
./ 表示当前目录下,即cpp所在目录下。
../表示上一目录下
水平投影 垂直投影找峰值点
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
double Otsu(Mat&image) {
int threshold = 0;
double maxVariance = 0;
double w0 = 0, w1 = 0;//前景与背景像素点所占比例
double u0 = 0, u1 = 0;//前景与背景像素值平均灰度
double histogram[256] = { 0 };
double Num = image.cols*image.rows;
//统计256个bin,每个bin像素的个数
for (int i = 0;i<image.rows;i++) {
const uchar * p = image.ptr<uchar>(i);
for (int j = 0;j<image.cols;j++) {
histogram[int(*p++)]++; //cout<<"Histogram[data[i*image.step+j]]++:;"<<histogram[int(*p++)]++<<endl;
}
}
//前景像素统计
for (int i = 0;i<255;i++) {
w0 = 0;
w1 = 0;
u0 = 0;
u1 = 0;
for (int j = 0;j <= i;j++) {
w0 = w0 + histogram[j];//以i为阈值,统计前景像素个数
u0 = u0 + j*histogram[j];//以i为阈值,统计前景像素灰度总和
}
w0 = w0 / Num;u0 = u0 / w0;
//背景像素统计
for (int j = i + 1;j <= 255;j++) {
w1 = w1 + histogram[j];//以i为阈值,统计前景像素个数
u1 = u1 + j*histogram[j];//以i为阈值,统计前景像素灰度总和
}
w1 = w1 / Num;u1 = u1 / w1;
double variance = w0*w1*(u1 - u0)*(u1 - u0); //当前类间方差计算
if (variance > maxVariance)
{
maxVariance = variance;
threshold = i;
}
}
cout << "threshold:" << threshold << endl;
return threshold;
}
int main()
{
Mat img = imread("123.jpg");
medianBlur(img, img, 3);
namedWindow("中值滤波", WINDOW_NORMAL);
imshow("中值滤波", img);
Mat img1;
img.copyTo(img1);
cvtColor(img, img, CV_BGR2GRAY);
cvtColor(img1, img1, CV_BGR2GRAY);
double th = Otsu(img);
cout << "The return value of getOstu is: " << th << endl;
//cout << "The return value of opencv threshold is: " << threshold(img1, img1, 0, 255, CV_THRESH_OTSU);//opencv已实现的大津法
for (int i = 0;i<img.rows;i++) {
for (int j = 0;j<img.cols;j++) {
if (img.data[i*img.step + j] <= th)
img.data[i*img.step + j] = 255;
else
img.data[i*img.step + j] = 0;
}
}
namedWindow("Ostu_二值化", WINDOW_NORMAL);
imshow("Ostu_二值化", img);
cv::Mat element0 = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));
for (int i = 0;i < 5;i++)
{
dilate(img, img, element0);
}
for (int i = 0;i<1;i++)
{
erode(img, img, element0);
}
namedWindow("形态学闭运算", WINDOW_NORMAL);
imshow("形态学闭运算", img);
std::vector<std::vector<cv::Point> > contours;
std::vector<std::vector<cv::Point> > max_contours;
std::vector<cv::Vec4i> hierarchy;
findContours(img, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE, cv::Point(0, 0));
vector<Point>points;//边缘点集合
vector<Point>centers;
int index = 0;
if (!contours.empty() && !hierarchy.empty())
{
for (std::vector<std::vector<cv::Point> >::iterator it = contours.begin();it != contours.end();)
{
if (fabs(contourArea(*it)) <10000 || fabs(contourArea(*it))>img.cols*img.rows/4)
{
it = contours.erase(it);
}
else
{
it++;
}
}
if (!contours.empty() )
{
Mat draw = Mat::zeros(img.size(), CV_8UC3);
Mat original = imread("./123.jpg");
drawContours(original, contours,
-1, // draw all contours
Scalar(0, 0, 255), // in white
2,8); // with a thickness of 2
drawContours(draw, contours,
-1, // draw all contours
Scalar(255, 0,0), // in white
2,8); // with a thickness of 2
namedWindow("Contours 筛选", WINDOW_NORMAL);
imshow("Contours 筛选", draw);
namedWindow("Contours on img",WINDOW_NORMAL);
imshow("Contours on img", original);
Mat original2 = imread("./123.jpg");
for (int i = 0;i<contours.size();i++)
{
RotatedRect minRect = minAreaRect(Mat(contours[i]));
Point2f rect_points[4];
minRect.points(rect_points);
for (int j = 0; j < 4; j++)
line(original2, rect_points[j], rect_points[(j + 1) % 4], Scalar(255, 255, 0), 2,8);
}
namedWindow("铭牌区域", WINDOW_NORMAL);
imshow("铭牌区域", original2);
}
}
//imshow("Opencv_img", img1);
waitKey(0);
return 0;
}
水平垂直投影
参考链接:https://www.cnblogs.com/jsxyhelu/p/9344585.html
//https://blog.csdn.net/m0_38025293/article/details/70182513
Mat horizontalProjection(Mat &srcImg)//水平投影
{
int perPixelValue = 0;//每个像素的值
int width = srcImg.cols;
int height = srcImg.rows;
int* projectValArry = new int[height];//创建一个储存每行白色像素个数的数组
memset(projectValArry, 0, height * 4);//初始化数组
for (int col = 0; col < height; col++)//遍历每个像素点
{
for (int row = 0; row < width; row++)
{
perPixelValue = srcImg.at<uchar>(col, row);
if (perPixelValue == 0)//如果是白底黑字
{
projectValArry[col]++;
}
}
}
Mat horizontalProjectionMat(height, width, CV_8UC1);//创建画布
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
perPixelValue = 255;
horizontalProjectionMat.at<uchar>(i, j) = perPixelValue;//设置背景为白色
}
}
for (int i = 0; i < height; i++)//水平直方图
{
for (int j = 0; j < projectValArry[i]; j++)
{
perPixelValue = 0;
horizontalProjectionMat.at<uchar>(i, width - 1 - j) = perPixelValue;//设置直方图为黑色
}
}
namedWindow("水平投影", WINDOW_NORMAL);
//imshow("水平投影", horizontalProjectionMat);
delete[] projectValArry;
return horizontalProjectionMat;
}
Mat verticalProjection(Mat &srcImg)//垂直投影
{
int perPixelValue;//每个像素的值
int width = srcImg.cols;
int height = srcImg.rows;
int* projectValArry = new int[width];//创建用于储存每列白色像素个数的数组
memset(projectValArry, 0, width * 4);//初始化数组
for (int col = 0; col < width; col++)
{
for (int row = 0; row < height;row++)
{
perPixelValue = srcImg.at<uchar>(row, col);
if (perPixelValue == 0)//如果是白底黑字
{
projectValArry[col]++;
}
}
}
Mat verticalProjectionMat(height, width, CV_8UC1);//垂直投影的画布
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
perPixelValue = 255; //背景设置为白色
verticalProjectionMat.at<uchar>(i, j) = perPixelValue;
}
}
for (int i = 0; i < width; i++)//垂直投影直方图
{
for (int j = 0; j < projectValArry[i]; j++)
{
perPixelValue = 0; //直方图设置为黑色
verticalProjectionMat.at<uchar>(height - 1 - j, i) = perPixelValue;
}
}
namedWindow("垂直投影", WINDOW_NORMAL);
//imshow("垂直投影", verticalProjectionMat);
delete[] projectValArry;
return verticalProjectionMat;
}
找轮廓质心
findContours(g_dstImage, contours, hierarcy, RETR_EXTERNAL, CHAIN_APPROX_NONE); //查找轮廓
vector<Rect> boundRect(contours.size()); //定义外接矩形集合
//计算轮廓矩
vector<Moments> mu(contours.size());
for (int i = 0; i < contours.size(); i++)
{
mu[i] = moments(contours[i], false);
}
//计算轮廓的质心
vector<Point2f> mc(contours.size());
for (int i = 0; i < contours.size(); i++)
{
mc[i] = Point2f(mu[i].m10 / mu[i].m00, mu[i].m01 / mu[i].m00);
}
if (!contours.empty())
{
cout << contours.size() << endl;
//cout << "contours.size():" << contours.size() << endl;
//筛选小面积干扰
vector<Moments> mu(contours.size());
for (int i = 0; i < contours.size(); i++)
{
mu[i] = moments(contours[i], false);
}
//计算轮廓的质心
vector<Point2f> mc(contours.size());
for (int i = 0; i < contours.size(); i++)
{
mc[i] = Point2f(mu[i].m10 / mu[i].m00, mu[i].m01 / mu[i].m00);
}
画轮廓及其质心
//Mat drawing = Mat::zeros(canny_output.size(), CV_8UC3);
//for (int i = 0; i< contours.size(); i++)
//{
// Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
// drawContours(drawing, contours, i, color, 2, 8, hierarchy, 0, Point());
// circle(drawing, mc[i], 4, color, -1, 8, 0);
vector<vector<Point>> contours2;
for (int i = 0; i < contours.size(); i++)
{
if (contourArea(Mat(contours[i])) > area && arcLength((Mat(contours[i])), false) > length)//根据面积排序小的干扰
{
if (fabs(mc[i].x- g_dstImage.cols/2) >gap )
{
contours2.push_back(contours[i]);
}
}
}
cout << contours2.size() << endl;
//cout << "contours.size():" << contours.size() << endl;
通过一阶矩对轮廓求质心
//vector<Moments> mu(contours.size());
Mat draw = Mat::zeros(g_dstImage.size(), g_dstImage.type());
drawContours(draw, contours2, -1, Scalar(255,255 ,255), -1, 8); //绘制轮廓
namedWindow("filter", WINDOW_NORMAL);
//imshow("filter", draw);
//形态学处理
Mat element = getStructuringElement(MORPH_RECT, Size(3, 3));
//erode(g_srcImage, g_srcImage, element);
erode(draw, draw, element);
dilate(draw,draw, element);
dilate(draw, draw, element);
dilate(draw, draw, element);
namedWindow("形态学处理", WINDOW_NORMAL);
//imshow("形态学处理", draw);
Mat h= horizontalProjection(draw);
Mat v= verticalProjection(draw);
cout << h.channels() << endl;
cout << v.channels() << endl;
Point p1(0, 0);
int b1 = 0;
for (int i = h.cols-60;i > 60;i--)
{
if (b1 == 0)
{
for (int j = h.rows-60;j > 60;j--)
{
//cout << "j" << endl;
if (int(h.at<uchar>(j, i)) >60 )
{
//p1.x = i;
p1.y = j;
b1 = 1;
break;
}
}
}
else
{
break;
}
}
bool b2 = 0;
for (int i = 60;i <v.rows-60;i++)
{
if (b2==0)
{
for (int j = 60;j < v.cols-60;j++)
{
if (v.at<uchar>(i, j) == 0)
{
p1.x = j;
//p2.y = i;
b2 = 1;
break;
}
}
}
else
{
break;
}
}
Point p2(draw.cols/2, draw.rows);
cout << p1 << endl;
cout << p2 << endl;
cout << "h.size()"<< h.size() << endl;
cout << "v.size()" << v.size() << endl;
cout << "draw.size()" << draw.size() << endl;
cvtColor(draw, draw, COLOR_GRAY2BGR);
line(draw, p1, p2, Scalar(255,0,0), 30, 8);
找最大的轮廓
vector<vector<Point>> contours;
//findContours的输入是二值图像
findContours(dst,
contours, // a vector of contours
RETR_EXTERNAL, // retrieve the external contours
CHAIN_APPROX_NONE); // retrieve all pixels of each contours
// Print contours' length轮廓的个数
//cout << "Contours: " << contours.size() << endl;
vector<float>contourArea;
//接下来对目标轮廓进行查找,目标是为了计算图像面积
//计算轮廓的面积并且存放
for (int i = 0; i < contours.size(); i++)
{
contourArea.push_back(cv::contourArea(contours[i]));
}
//找出面积最大的轮廓
double maxValue; Point maxLoc;
minMaxLoc(contourArea, NULL, &maxValue, NULL, &maxLoc);
//计算面积最大的轮廓的最小的外包矩形
//RotatedRect minRect = minAreaRect(contours[maxLoc.x]);
Rect r = boundingRect(contours[maxLoc.x]);