一,利用面積對輪廓進行篩選
注意這種面積篩選有一個弊端就是比如有兩個輪廓,
A輪廓為500
B輪廓為300
當面積設置為 area<400時就可以篩選出面積小于300的所有輪廓
反之大于300的輪廓 如果有兩個圓輪廓一大一小,可能就只能保留一個了
如果知道這兩個形狀的輪廓面積,或許可以利用 邏輯與? 進行篩選。
效果圖
//圓心
#include<iostream>
#include<opencv2\opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
//載入圖像
Mat src = imread("D:\\Besktop\\faimage\\Image\\21_25_27.bmp");
Mat src_clone = src.clone();
if (src.empty())
{
cout << "圖片為空" << endl;
return 0;
}
imshow("src", src);
//轉灰度圖
Mat gray;
cvtColor(src, gray, COLOR_BGR2GRAY);
//圖像二值化
threshold(gray, gray, 0, 255, THRESH_BINARY | THRESH_OTSU);
imshow("threshold", gray);
//執(zhí)行形態(tài)學開操作去除噪點
/*Mat kernel = getStructuringElement(MORPH_RECT, Size(3,3), Point(-1, -1));
morphologyEx(gray, gray, MORPH_OPEN, kernel, Point(-1, -1), 1);
imshow("morphologyEx", gray);*/
//邊緣檢測
Canny(gray, gray, 0, 255);
Mat graycanny;
resize(gray, graycanny, Size(600, 600));
imshow("canny", graycanny);
//輪廓發(fā)現(xiàn)
vector<vector<Point>> contours;
vector<Vec4i> her;
findContours(gray, contours, her, RETR_TREE, CHAIN_APPROX_SIMPLE);
//獲取某一輪廓重心點
Moments M;
M = moments(contours[0]);
double cX = double(M.m10 / M.m00);
double cY = double(M.m01 / M.m00);
//Mat resultImage = Mat::zeros(gray.size(), CV_8UC3);
RNG rng(12345);
double area = 0.0;
Point pRadius;
for (int i = 0; i < contours.size(); i++) {
double area = contourArea(contours[i], false);
//根據(jù)面積及縱橫比過濾輪廓
if (area > 200) {
Rect rect = boundingRect(contours[i]);
float scale = float(rect.width) / float(rect.height);
if (scale < 1 && scale>0) {
drawContours(gray, contours, i, Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), -1);
int x = rect.width / 2;
int y = rect.height / 2;
//找出圓心并繪制
pRadius = Point(rect.x + x, rect.y + y);
circle(gray, pRadius, 15, Scalar(0, 0, 255), 15);
}
}
}
Mat graycanny1;
resize(gray, graycanny1, Size(600, 600));
imshow("resultImage", graycanny1);
//imshow("resultImage", resultImage);
//在原圖上繪制圓心
circle(src_clone, pRadius, 15, Scalar(0, 0, 255), 15);
cout << "圓心坐標:" << cX << "" << cY << endl;
//cout <<"[x,y]" << pRadius << endl;
Mat graycanny2;
resize(src_clone, graycanny2, Size(600, 600));
imshow("src_clone", graycanny2);
//imshow("src_clone", src_clone);
waitKey(0);
return 0;
}
二,利用邊緣檢測和輪廓篩選找出輪廓
這一種則是利用輪廓的中心點對輪廓進行擬合,從而達到尋找輪廓
#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat img = imread("D:\\Besktop\\faimage\\測試原圖\\22_21_27.bmp");
//String dest = "D:\\Besktop\\1\\";
/*string path = "D:\\Besktop\\faimage\\測試原圖\\";
String dest = "D:\\Besktop\\1\\";
String savedfilename;
int len = path.length();
vector<cv::String> filenames;
cv::glob(path, filenames);
for (int i = 0; i < filenames.size(); i++)
Mat frame;
frame = imread(filenames[i], i);
savedfilename = dest + filenames[i].substr(len);*/
Mat gray_img, thresh_img;
//灰度
cvtColor(img, gray_img, COLOR_BGR2GRAY);
threshold(gray_img, thresh_img, 0, 255, THRESH_TRIANGLE);
//開運算
Mat ellipse = getStructuringElement(MORPH_ELLIPSE, Size(13, 13));
morphologyEx(thresh_img, thresh_img, MORPH_OPEN, ellipse, Point(-1, -1), 2);
//尋找輪廓
vector<vector<Point>> contours;
vector<Vec4i> hierarchy1;
findContours(thresh_img, contours, hierarchy1, RETR_LIST, CHAIN_APPROX_NONE, Point());
//獲取某一輪廓重心點
Moments M;
M = moments(contours[0]);
double cX = double(M.m10 / M.m00);
double cY = double(M.m01 / M.m00);
//繪制輪廓
drawContours(img, contours, 0, Scalar(0, 255, 0), 2, 8, hierarchy1);
//顯示輪廓重心并提取坐標點
circle(img, Point2d(cX, cY), 6, Scalar(0, 255, 0), 2, 8);
namedWindow("Center Point", CV_WINDOW_NORMAL);
imshow("Center Point", img);
//imwrite("D:\\Besktop\\1\\22_21_27.bmp", img);
putText(img, "center", Point2d(cX - 20, cY - 20), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 255, 0), 1, 8);
cout << "重心坐標:" << cX << " " << cY << endl << endl;
waitKey(0);
return 0;
}
三,這一種方法類似于第一種的面積篩選唯一不同的時候增加了幾步形態(tài)學處理
?
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;
//第二步 通過面積過濾,通過縱橫比的測量,圓形的縱橫比應該在1:1左右,如果不是1:1,就把它過濾掉
Mat srcImg, binaryImg, dstImg;
void test()
{
srcImg = imread("D:\\Besktop\\faimage\\Image\\21_25_27.bmp", IMREAD_GRAYSCALE);
if (srcImg.empty())
{
cout << "could not load image...\n" << endl;
}
namedWindow("Original image", CV_WINDOW_NORMAL); //CV_WINDOW_NORMAL 使得鼠標可以控制顯示窗口的大小
imshow("Original image", srcImg);
//二值化
threshold(srcImg, binaryImg, 0, 255, THRESH_BINARY | THRESH_OTSU);
namedWindow("Binary Result", CV_WINDOW_NORMAL);
imshow("Binary Result", binaryImg);
//形態(tài)學操作,開操作,去掉小的對象,閉操作,連接里面的洞(開閉操作要先獲得結構元素)
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1)); //Point(-1, -1)是中心點,這里是 2 x 2位置
morphologyEx(binaryImg, dstImg, MORPH_CLOSE, kernel, Point(-1, -1));
namedWindow("Close Result", CV_WINDOW_NORMAL);
imshow("Close Result", dstImg);
kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
morphologyEx(dstImg, dstImg, MORPH_OPEN, kernel, Point(-1, -1));
namedWindow("Open Result", CV_WINDOW_NORMAL);
imshow("Open Result", dstImg);
//輪廓發(fā)現(xiàn)
vector<vector<Point>> contours; //存儲輪廓
vector<Vec4i> hireachy;
findContours(dstImg, contours, hireachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point());
//通過面積過濾,通過縱橫比的測量,圓形的縱橫比應該在1:1左右,如果不是1:1,就把它過濾掉
Mat resultImg = Mat::zeros(srcImg.size(), CV_8SC3);
Point cc;
for (int i = 0; i < contours.size(); i++)
{
//面積過濾
double area = contourArea(contours[i]); //循環(huán)獲取指定的面積
if (area < 100) //通過循環(huán)過濾掉小于100的面積
continue;
//橫縱比過濾
Rect rect = boundingRect(contours[i]);
float ratio = float(rect.width) / float(rect.height);
if (ratio < 1.1 && ratio> 0.9) //把滿足條件的保留畫出來
{
drawContours(resultImg, contours, i, Scalar(0, 0, 255), -1, 8, Mat(), 0, Point()); //畫出來 第五個參數(shù)改為 -1 ,使得整個圓形填充
cout << "circle area: " << area << endl; //面積和周長打印出來(像素度量)
cout << "circle length: " << arcLength(contours[i], true) << endl;
//找中心點
int x = rect.x + rect.width / 2;
int y = rect.y + rect.height / 2;
cc = Point(x, y);
circle(resultImg, cc, 2, Scalar(0, 0, 255), 2, 8, 0); //畫出中心點
}
}
namedWindow("Final Result", CV_WINDOW_NORMAL);
imshow("Final Result", resultImg);
//在原圖上定位顯示中心點
Mat circleImg = srcImg.clone();
cvtColor(circleImg, circleImg, COLOR_GRAY2BGR);
circle(circleImg, cc, 20, Scalar(0, 0, 255), 2, 8, 0);
namedWindow("Center Point", CV_WINDOW_NORMAL);
imshow("Center Point", circleImg);
}
int main()
{
test();
waitKey(0);
return 0;
}
這三種方法都是opencv中的一些方法,有任何建議和問題均可評論區(qū)提問,說不定你的建議正是我疑惑的地方?。?!
四,利用輪廓擬合的方法對圖片中的某個輪廓進行擬合(這里主要是圓心)
此方法運行環(huán)境為opencv4.5.5
?相關代碼
#if 1
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
// 讀取圖片
Mat src = imread("圖片路徑");
// 轉換為灰度圖
Mat gray;
cvtColor(src, gray, COLOR_BGR2GRAY);
// 進行邊緣檢測
Mat edge;
Canny(gray, edge, 100, 200);
// 圓形擬合
vector<Vec3f> circles;
HoughCircles(edge, circles, HOUGH_GRADIENT, 1, edge.rows / 16, 100, 30, 10, 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]);
circle(src, center, radius, Scalar(0, 0, 255), 2);
circle(src, center, 3, Scalar(0, 255, 0), -1);
}
// 顯示結果
namedWindow("src", WINDOW_NORMAL);
imshow("src", src);
waitKey(0);
return 0;
}
#endif // 1
五,這種是利用凸包 對圓形進行擬合并且將所有的輪廓都繪制外界圓
opencv4.5.5
?代碼文章來源:http://www.zghlxwxcb.cn/news/detail-675107.html
#if 1
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
// 讀取圖片
Mat img = imread("圖片路徑");
// 轉換為灰度圖
Mat gray;
cvtColor(img, gray, COLOR_BGR2GRAY);
// 進行二值化處理
Mat thresh;
threshold(gray, thresh, 128, 255, THRESH_BINARY);
// 找到所有輪廓
vector<vector<Point>> contours;
findContours(thresh, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
// 遍歷輪廓,找到圓形輪廓
for (size_t i = 0; i < contours.size(); i++)
{
// 只考慮凸包
vector<Point> hull;
convexHull(contours[i], hull);
// 嘗試將輪廓擬合為圓形
Point2f center;
float radius;
//bool isCircle = fitCircle(hull, center, radius);
minEnclosingCircle(hull, center, radius);
cout << center.x << "," << center.y << endl;
// 標出圓心
circle(img, center, 5, Scalar(0, 255, 0), -1);
// 繪制圓形
circle(img, center, radius, Scalar(0, 0, 255), 2);
}
// 顯示結果
Mat ss;
resize(img, ss, Size(600, 600));
imshow("Contours", ss);
waitKey();
}
#endif // 0
有問題歡迎評論區(qū)討論文章來源地址http://www.zghlxwxcb.cn/news/detail-675107.html
到了這里,關于C++opencv找圓心?看著一篇,一定有你要(邊緣輪廓檢測,擬合,凸包)找出相應的輪廓或者全部輪廓畫外界圓輪廓并且標出輪廓中心的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!