效果
代碼
#include <iostream>
#include <string>
#include <sstream>
#include <cmath>
//#include <memory>
using namespace std;
// OpenCV includes
#include "opencv2/core/utility.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
using namespace cv;
// OpenCV command line parser functions
// Keys accecpted by command line parser
const char *keys =
{
"{help h usage ? || print this message}"
"{@image1 | /opencv4_vscode/opencv4例程/Chapter_05/data/test.pgm| Image1 to process}"
"{@image2 | /opencv4_vscode/opencv4例程/Chapter_05/data/light.pgm| Image2 to process}"
"{@segMethod |1| method=0使用除法,method=1使用減法}"
"{@conMethod |1| method=0使用connectComponents();method=1使用connectComponentsWithStats();method=2 僅僅畫出輪廓}"};
//獲取光模式或相似背景
Mat calculateLightPattern(Mat img)
{
Mat result;
blur(img, result, Size(img.cols / 3, img.rows / 3));
return result;
}
//獲取一個沒有光/背景的新圖像,method=0使用除法,method=1使用減法
Mat RemoveLight(Mat img, Mat background, int method)
{
Mat result;
//background.copyTo(result);
if (method == 0)
{
Mat img32, background32;
img.convertTo(img32, CV_32F);
background.convertTo(background32, CV_32F);
result = 1 - (img32 / background32);
result.convertTo(result, CV_8U, 255);
}
if (method == 1)
{
result = background - img;
}
return result;
}
//獲取二值化後的圖像,方便分割。當使用除法獲取無背景圖像時,method=0,否則,method =1;
Mat twoValue(Mat image, int method)
{
Mat result;
int Threshold = 10, type = THRESH_BINARY;
if (method == 0)
{
Threshold = 10, type = THRESH_BINARY;
}
else
{
Threshold = 20, type = THRESH_BINARY;
}
threshold(image, result, Threshold, 255, type);
return result;
}
//獲取分割後的圖像。method=0使用connectComponents();method=1使用connectComponentsWithStats();method=2 僅僅畫出輪廓
void imageSegmentation(Mat img, int method)
{
Mat labels, stats, centroids;
RNG rng(12345);
//creat output image coloring the objects and show area
Mat output = Mat::zeros(img.rows, img.cols, CV_8UC3);
//use connected components to divide our image in multiple connected component objects
if (method == 0)
{
auto num_objects = connectedComponents(img, labels);
if (num_objects < 2)
{
cout << "no objects detected" << endl;
return;
}
else
{
cout << "Number of objects detected: " << num_objects - 1 << endl;
}
for (auto i = 1; i < num_objects; i++)
{
Mat mask = labels == i;
output.setTo(Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), mask);
}
}
//use connected components with stats to divide our image in multiple connected component objects
if (method == 1)
{
auto num_objects = connectedComponentsWithStats(img, labels, stats, centroids);
if (num_objects < 2)
{
cout << "no objects detected" << endl;
return;
}
else
{
cout << "Number of objects detected: " << num_objects - 1 << endl;
}
for (auto i = 1; i < num_objects; i++)
{
cout << "Object" << i << "with pos: " << centroids.at<Point2d>(i) << "with area " << stats.at<int>(i, CC_STAT_AREA) << endl;
Mat mask = labels == i;
output.setTo(Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), mask);
//draw text with area
stringstream ss;
ss << "area: " << stats.at<int>(i, CC_STAT_AREA);
putText(output, ss.str(), centroids.at<Point2d>(i), FONT_HERSHEY_SIMPLEX, 0.4, Scalar(255, 255, 255));
}
}
//use findContours to draw contours
if (method == 2)
{
vector<vector<Point>> contours;
findContours(img, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
//check the number of objects detected
if (contours.size() == 0)
{
cout << "No objects detected" << endl;
return;
}
else
{
cout << "Number of objects detected: " << contours.size() << endl;
}
//draw contours
for (auto i = 0; i < contours.size(); i++)
{
drawContours(output, contours, i, Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), 1, LINE_8, Mat());
//imshow("output", output);
}
}
imshow("output", output);
}
int main(int argc, const char **argv)
{
CommandLineParser parser(argc, argv, keys);
parser.about("Chapter 4. PhotoTool v1.0.0");
//If requires help show
if (parser.has("help"))
{
parser.printMessage();
return 0;
}
String imgFile1 = parser.get<String>(0);
String imgFile2 = parser.get<string>(1);
int sMethod = parser.get<int>(2);
int cMethod = parser.get<int>(3);
// Check if params are correctly parsed in his variables
if (!parser.check())
{
parser.printErrors();
return 0;
}
Mat test = imread(imgFile1); //輸入測試圖片
Mat background = imread(imgFile2); //輸入背景圖片
Mat blured;
medianBlur(test, blured, 3); //消除噪點
Mat Removed_Light = RemoveLight(blured, background, sMethod); //移除背景
cvtColor(Removed_Light, Removed_Light, COLOR_BGR2GRAY);
medianBlur(Removed_Light, Removed_Light, 3);
Mat binary_img = twoValue(Removed_Light, sMethod); //二值化
imshow("binary_img ", binary_img);
imageSegmentation(binary_img, cMethod);
waitKey(0);
return 0;
}