c++
cv::HoughLinesP(
InputArray src, // 输入图像,必须8-bit的灰度图像
OutputArray lines, // 输出的极坐标来表示直线
double rho, // 生成极坐标时候的像素扫描步长
double theta, //生成极坐标时候的角度步长,一般取值CV_PI/180
int threshold, // 阈值,只有获得足够交点的极坐标点才被看成是直线
double minLineLength=0;// 最小直线长度
double maxLineGap=0;// 最大间隔
)
c++
Mat src, src_gray,dst;
src = imread("C:\\Users\\15646\\Pictures\\线条.jpg");
//边缘检测
Canny(src, src_gray, 150, 200);
//灰度转彩色
cvtColor(src_gray, dst, CV_GRAY2BGR);
//霍夫直线检测
vector<Vec4f> plines;
HoughLinesP(src_gray, plines, 1, CV_PI / 180.0, 10, 0, 10);
Scalar color = Scalar(0, 0, 255);
for (size_t i = 0; i < plines.size(); i++)
{
Vec4f hline = plines[i];
line(dst, Point(hline[i], hline[1]), Point(hline[2], hline[3]), color,3, LINE_AA);
}
imshow("dst img", dst);
c++
HoughCircles(
InputArray image, // 输入图像 ,必须是8位的单通道灰度图像
OutputArray circles, // 输出结果,发现的圆信息
Int method, // 方法 - HOUGH_GRADIENT
Double dp, // dp = 1;
Double mindist, // 10 最短距离-可以分辨是两个圆的,否则认为是同心圆- src_gray.rows/8
Double param1, // canny edge detection low threshold
Double param2, // 中心点累加器阈值 – 候选圆心
Int minradius, // 最小半径
Int maxradius//最大半径
)
c++
Mat src, dst;
src = imread("C:\\Users\\Administrator\\Pictures\\霍夫圆检测4.jpg");
imshow("src img", src);
//中值滤波转灰度
Mat mediaImg;
medianBlur(src, mediaImg, 3);
cvtColor(mediaImg, mediaImg, CV_BGR2GRAY);
GaussianBlur(mediaImg,mediaImg, Size(5, 5), 0, 0);
//霍夫圆检测
vector<Vec3f> pcircle;
HoughCircles(mediaImg, pcircle, CV_HOUGH_GRADIENT, 1, 10, 100, 30, 5, 50);
src.copyTo(dst);
for (size_t i = 0; i < pcircle.size(); i++)
{
Vec3f cc = pcircle[i];
//圆形标注
circle(dst, Point(cc[0], cc[1]), cc[2], Scalar(0, 0, 255), 2, LINE_AA);
//圆心标注
circle(dst, Point(cc[0], cc[1]), 2, Scalar(198, 50, 255), 2, LINE_AA);
}
imshow("hough img", dst);
简单点说就是把输入图像中各个像素按照一定的规则映射到另外一张图像的对应位置上去,形成一张新的图像。
c++
Remap(
InputArray src,// 输入图像
OutputArray dst,// 输出图像
InputArray map1,// x 映射表 CV_32FC1/CV_32FC2
InputArray map2,// y 映射表
int interpolation,// 选择的插值方法,常见线性插值,可选择立方等
int borderMode,// BORDER_CONSTANT
const Scalar borderValue// color
)
c++
#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
using namespace cv;
Mat src, dst, map_x, map_y;
const char* OUTPUT_TITLE = "remap demo";
int index = 0;
void update_map(void);
int main(int argc, char** argv) {
src = imread("C:\\Users\\Administrator\\Pictures\\girl2.jpg");
if (!src.data) {
printf("could not load image...\n");
return -1;
}
char input_win[] = "input image";
namedWindow(input_win, CV_WINDOW_AUTOSIZE);
namedWindow(OUTPUT_TITLE, CV_WINDOW_AUTOSIZE);
imshow(input_win, src);
map_x.create(src.size(), CV_32FC1);
map_y.create(src.size(), CV_32FC1);
int c = 0;
while (true) {
c = waitKey(500);
//按住esc退出
if ((char)c == 27) {
break;
}
//键盘输入1,2,3,4
index = c % 4;
update_map();
remap(src, dst, map_x, map_y, INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 255, 255));
imshow(OUTPUT_TITLE, dst);
}
return 0;
}
void update_map(void) {
for (int row = 0; row < src.rows; row++) {
for (int col = 0; col < src.cols; col++) {
switch (index) {
//缩小一半
case 0:
if (col >(src.cols * 0.25) && col <= (src.cols*0.75) && row >(src.rows*0.25) && row <= (src.rows*0.75)) {
map_x.at<float>(row, col) = 2 * (col - (src.cols*0.25));
map_y.at<float>(row, col) = 2 * (row - (src.rows*0.25));
}
else {
map_x.at<float>(row, col) = 0;
map_y.at<float>(row, col) = 0;
}
break;
//x方向对调
case 1:
map_x.at<float>(row, col) = (src.cols - col - 1);
map_y.at<float>(row, col) = row;
break;
//y方向对调
case 2:
map_x.at<float>(row, col) = col;
map_y.at<float>(row, col) = (src.rows - row - 1);
break;
//x,y方向都对调
case 3:
map_x.at<float>(row, col) = (src.cols - col - 1);
map_y.at<float>(row, col) = (src.rows - row - 1);
break;
}
}
}
}
图像直方图,是指对整个图像像在灰度范围内的像素值(0~255)统计出现频率次数,据此生成的直方图,称为图像直方图-直方图。直方图反映了图像灰度的分布情况。是图像的统计学特征。
是一种提高图像对比度的方法,拉伸图像灰度值范围。
如何实现,通过上一课中的remap我们知道可以将图像灰度分布从一个分布映射到另外一个分布,然后在得到映射后的像素值即可。
c++
equalizeHist(
InputArray src,//输入图像,必须是8-bit的单通道图像
OutputArray dst// 输出结果
)
c++
split(// 把多通道图像分为多个单通道图像
const Mat &src, //输入图像
Mat* mvbegin)// 输出的通道图像数组
calcHist(
const Mat* images,//输入图像指针
int images,// 图像数目
const int* channels,// 通道数
InputArray mask,// 输入mask,可选,不用
OutputArray hist,//输出的直方图数据
int dims,// 维数
const int* histsize,// 直方图级数
const float* ranges,// 值域范围
bool uniform,// true by default
bool accumulate// false by defaut
)
对输入的两张图像计算得到直方图H1与H2,归一化到相同的尺度空间 然后可以通过计算H1与H2的之间的距离得到两个直方图的相似程度进 而比较图像本身的相似程度。
Opencv提供的比较方法有四种:
Code
compareHist(
InputArray h1, // 直方图数据,下同
InputArray H2,
int method// 比较方法,上述四种方法之一
)
c++
Mat src, dst;
src = imread("C:\\Users\\15646\\Pictures\\刘亦菲.jpg");
//分通道显示
vector<Mat> bgr_planes;
split(src, bgr_planes);
int histSize = 256;
float range[] = { 0,256 };
const float *histRange = { range };
Mat b_hist, g_hist, r_hist;
calcHist(&bgr_planes[0], 1, 0, Mat(), b_hist, 1, &histSize, &histRange, true, false);
calcHist(&bgr_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRange, true, false);
calcHist(&bgr_planes[2], 1, 0, Mat(), r_hist, 1, &histSize, &histRange, true, false);
//归一化
int hist_h = 200;
int hist_w = 300;
int bin_w = hist_w / histSize;
Mat histImage(hist_w, hist_h, CV_8UC3, Scalar(0, 0, 0));
normalize(b_hist, b_hist, 0, hist_h, NORM_MINMAX, -1, Mat());
normalize(g_hist, g_hist, 0, hist_h, NORM_MINMAX, -1, Mat());
normalize(r_hist, r_hist, 0, hist_h, NORM_MINMAX, -1, Mat());
//绘制直方图
for (int i = 0; i < histSize; i++)
{
line(histImage, Point((i - 1)*bin_w, hist_h - cvRound(b_hist.at<float>(i - 1))),
Point((i)*bin_w, hist_h - cvRound(b_hist.at<float>(i))), Scalar(255, 0, 0), LINE_AA);
line(histImage, Point((i - 1)*bin_w, hist_h - cvRound(g_hist.at<float>(i - 1))),
Point((i)*bin_w, hist_h - cvRound(g_hist.at<float>(i))), Scalar(255, 0, 0), LINE_AA);
line(histImage, Point((i - 1)*bin_w, hist_h - cvRound(r_hist.at<float>(i - 1))),
Point((i)*bin_w, hist_h - cvRound(r_hist.at<float>(i))), Scalar(255, 0, 0), LINE_AA);
}
imshow("src img", histImage);
c++
加载图片imread
将图像从RGB色彩空间转换到HSV色彩空间cvtColor
计算直方图和归一化calcHist与normalize
Mat与MatND其中Mat表示二维数组,MatND表示三维或者多维数据,此处均可以用Mat表示。
计算反向投影图像 - calcBackProject
Mat src, hsv, hue;
int bins = 12;
string src_img = "src img";
void Hist_Add_Backproject(int, void*);
int main(int argc, char * argv) {
src = imread("C:\\Users\\15646\\Pictures\\lab\\test1.png");
namedWindow(src_img, WINDOW_AUTOSIZE);
cvtColor(src, hsv, CV_BGR2HSV);
hue.create(hsv.size(), hsv.depth());
int nchannels[] = { 0,0 };
mixChannels(&hsv, 1, &hue, 1, nchannels, 1);
createTrackbar("Histogram Bins", src_img, &bins, 180, Hist_Add_Backproject);
Hist_Add_Backproject(0, 0);
imshow(src_img, src);
waitKey(0);
return 0;
}
void Hist_Add_Backproject(int, void*) {
float range[] = { 0,180 };
const float *histRanges = { range };
Mat h_hist;
calcHist(&hue, 1, 0, Mat(), h_hist, 1, &bins, &histRanges, true, false);
normalize(h_hist, h_hist, 0, 255, NORM_MINMAX, -1, Mat());
Mat backPrjImage;
calcBackProject(&hue, 1, 0, h_hist, backPrjImage, &histRanges, 1, true);
imshow("BackProj", backPrjImage);
int hist_h = 400;
int hist_w = 400;
Mat histImage(hist_w, hist_h, CV_8UC3, Scalar(0, 0, 0));
int bin_w = cvRound((double)hist_w / bins);
for (int i = 1; i < bins; i++)
{
rectangle(histImage,
Point((i - 1)*bin_w, (hist_h - cvRound(h_hist.at<float>(i - 1)*(400 / 255)))),
Point(i*bin_w, hist_h),
Scalar(0, 0, 255), -1);
}
imshow("Histogram", histImage);
}
c++
matchTemplate(
InputArray image,// 源图像,必须是8-bit或者32-bit浮点数图像
InputArray templ,// 模板图像,类型与输入图像一致
OutputArray result,// 输出结果,必须是单通道32位浮点数,假设源图像WxH,模板图像wxh,
则结果必须为W-w+1, H-h+1的大小。
int method,//使用的匹配方法
InputArray mask=noArray()//(optional)
)
c++
#include<opencv2\opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
Mat src, dst, temp;
int match_method = CV_TM_SQDIFF;
int max_track = 5;
string inputImg = "input img";
string outputImg = "output img";
string matchimg = "template match-demo";
void Match_Demo(int, void*);
int main(int argc, char * argv) {
src = imread("C:\\Users\\15646\\Pictures\\雷军.jpg");
temp = imread("C:\\Users\\15646\\Pictures\\雷军头像.jpg");
namedWindow(inputImg, CV_WINDOW_AUTOSIZE);
namedWindow(outputImg, CV_WINDOW_AUTOSIZE);
namedWindow(matchimg, CV_WINDOW_AUTOSIZE);
imshow(inputImg, src);
createTrackbar("Macth Control", inputImg, &match_method, max_track, Match_Demo);
Match_Demo(0, 0);
waitKey(0);
return 0;
}
void Match_Demo(int, void*) {
int width = src.cols - temp.cols + 1;
int height = src.rows - temp.rows + 1;
Mat result(width, height, CV_32FC1);
matchTemplate(src,temp,result,match_method,Mat());
normalize(result, result, 0, 1, NORM_MINMAX, -1, Mat());
Point minLoc;
Point maxLoc;
double min, max;
src.copyTo(dst);
Point tenLoc;
minMaxLoc(result, &min, &max, &minLoc, &maxLoc, Mat());
if (match_method==CV_TM_SQDIFF || match_method == CV_TM_SQDIFF_NORMED)
{
tenLoc = minLoc;
}
else {
tenLoc = maxLoc;
}
//绘制矩形
rectangle(dst, Rect(tenLoc.x, tenLoc.y, temp.cols, temp.rows), Scalar(0, 0, .255), 2, 8);
rectangle(result, Rect(tenLoc.x, tenLoc.y, temp.cols, temp.rows), Scalar(0, 0, .255), 2, 8);
imshow(outputImg, result);
imshow(matchimg, dst);
}
Code
在二值图像上发现轮廓使用API cv::findContours(
InputOutputArray binImg, // 输入图像,非0的像素被看成1,0的像素值保持不变,8-bit
OutputArrayOfArrays contours,// 全部发现的轮廓对象
OutputArray, hierachy// 图该的拓扑结构,可选,该轮廓发现算法正是基于图像拓扑结构实现。
int mode, // 轮廓返回的模式
int method,// 发现方法
Point offset=Point()// 轮廓像素的位移,默认(0, 0)没有位移
)
c++
在二值图像上发现轮廓使用API cv::findContours之后对发现的轮廓数据进行绘制显示
drawContours(
InputOutputArray binImg, // 输出图像
OutputArrayOfArrays contours,// 全部发现的轮廓对象
Int contourIdx// 轮廓索引号
const Scalar & color,// 绘制时候颜色
int thickness,// 绘制线宽
int lineType ,// 线的类型LINE_8
InputArray hierarchy,// 拓扑结构图
int maxlevel,// 最大层数, 0只绘制当前的,1表示绘制绘制当前及其内嵌的轮廓
Point offset=Point()// 轮廓位移,可选
)
c++
using namespace std;
using namespace cv;
Mat src, dst;
int threshold_value = 100;
int threshold_max = 255;
RNG rng;
void Demo_Countours(int, void*);
string input_title = "input img";
string output_title = "output img";
int main(int argc, char * argv) {
src = imread("C:\\Users\\15646\\Pictures\\lab\\山羊.jfif");
namedWindow(input_title, CV_WINDOW_AUTOSIZE);
namedWindow(output_title, CV_WINDOW_AUTOSIZE);
imshow(input_title, src);
//图像灰度化
cvtColor(src, src, CV_BGR2GRAY);
createTrackbar("control img", output_title, &threshold_value, threshold_max, Demo_Countours);
Demo_Countours(0, 0);
waitKey(0);
return 0;
}
void Demo_Countours(int, void*) {
Mat canny_output;
vector<vector<Point>> contours;
vector<Vec4i>hierachy;
//图像边缘检测二值化
Canny(src, canny_output, threshold_value, threshold_value * 2, 3, false);
//轮廓发现
findContours(canny_output, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
dst = Mat::zeros(src.size(), CV_8UC3);
rng(12345);
for (size_t i = 0; i < contours.size(); i++)
{
Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
//轮廓绘制
drawContours(dst, contours, i, color, 2, 8, hierachy, 0, Point(0, 0));
}
imshow(output_title, dst);
}
什么是凸包(Convex Hull),在一个多变形边缘或者内部任 意两个点的连线都包含在多边形边界或者内部。
包含点集合S中所有点的最小凸多边形称为凸包
Code
convexHull(
InputArray points,// 输入候选点,来自findContours
OutputArray hull,// 凸包
bool clockwise,// default true, 顺时针方向
bool returnPoints)// true 表示返回点个数,如果第二个参数是 vector<Point>则自动忽略
)
c++
#include<opencv2\opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
Mat src,gray_src, dst;
int threshold_value = 100;
int threshold_max = 255;
RNG rng;
void Demo_Countours(int, void*);
string input_title = "input img";
string output_title = "output img";
int main(int argc, char * argv) {
src = imread("C:\\Users\\15646\\Pictures\\lab\\test2.png");
namedWindow(input_title, CV_WINDOW_AUTOSIZE);
namedWindow(output_title, CV_WINDOW_AUTOSIZE);
imshow(input_title, src);
//图像灰度化
cvtColor(src, gray_src, CV_BGR2GRAY);
//模糊
blur(gray_src, gray_src, Size(3, 3), Point(-1, -1), BORDER_DEFAULT);
createTrackbar("control img", output_title, &threshold_value, threshold_max, Demo_Countours);
Demo_Countours(0, 0);
waitKey(0);
return 0;
}
void Demo_Countours(int, void*) {
Mat bin_output;
vector<vector<Point>> contours;
vector<Vec4i>hierachy;
//设置阈值,阈值二值化
threshold(gray_src, bin_output, threshold_value, threshold_max, THRESH_BINARY);
//发现轮廓
findContours(bin_output, contours, hierachy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point(0, 0));
vector<vector<Point>> convexs(contours.size());
for (size_t i = 0; i < contours.size(); i++)
{
convexHull(contours[i], convexs[i], false, true);
}
//绘制
dst = Mat::zeros(src.size(), CV_8UC3);
vector<Vec4i>empty(0);
for (size_t i = 0; i < contours.size(); i++)
{
Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
drawContours(dst, contours, i, color,2, LINE_8, hierachy, 0, Point(0, 0));
drawContours(dst, convexs, i, color, 2, LINE_8, empty, 0, Point(0, 0));
}
imshow(output_title, dst);
}
c++
#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
using namespace std;
using namespace cv;
Mat src, gray_src, drawImg;
int threshold_v = 170;
int threshold_max = 255;
const char* output_win = "rectangle-demo";
RNG rng(12345);
void Contours_Callback(int, void*);
int main(int argc, char** argv) {
src = imread("C:\\Users\\15646\\Pictures\\lab\\热气球.jfif");
if (!src.data) {
printf("could not load image...\n");
return -1;
}
cvtColor(src, gray_src, CV_BGR2GRAY);
blur(gray_src, gray_src, Size(3, 3), Point(-1, -1));
const char* source_win = "input image";
namedWindow(source_win, CV_WINDOW_AUTOSIZE);
namedWindow(output_win, CV_WINDOW_AUTOSIZE);
imshow(source_win, src);
createTrackbar("Threshold Value:", output_win, &threshold_v, threshold_max, Contours_Callback);
Contours_Callback(0, 0);
waitKey(0);
return 0;
}
void Contours_Callback(int, void*) {
Mat binary_output;
vector<vector<Point>> contours;
vector<Vec4i> hierachy;
threshold(gray_src, binary_output, threshold_v, threshold_max, THRESH_BINARY);
//imshow("binary image", binary_output);
findContours(binary_output, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(-1, -1));
vector<vector<Point>> contours_ploy(contours.size());
vector<Rect> ploy_rects(contours.size());
vector<Point2f> ccs(contours.size());
vector<float> radius(contours.size());
vector<RotatedRect> minRects(contours.size());
vector<RotatedRect> myellipse(contours.size());
for (size_t i = 0; i < contours.size(); i++) {
approxPolyDP(Mat(contours[i]), contours_ploy[i], 3, true);
ploy_rects[i] = boundingRect(contours_ploy[i]);
minEnclosingCircle(contours_ploy[i], ccs[i], radius[i]);
if (contours_ploy[i].size() > 5) {
myellipse[i] = fitEllipse(contours_ploy[i]);
minRects[i] = minAreaRect(contours_ploy[i]);
}
}
// draw it
drawImg = Mat::zeros(src.size(), src.type());
Point2f pts[4];
for (size_t t = 0; t < contours.size(); t++) {
Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
//rectangle(drawImg, ploy_rects[t], color, 2, 8);
//circle(drawImg, ccs[t], radius[t], color, 2, 8);
if (contours_ploy[t].size() > 5) {
ellipse(drawImg, myellipse[t], color, 1, 8);
minRects[t].points(pts);
for (int r = 0; r < 4; r++) {
line(drawImg, pts[r], pts[(r + 1) % 4], color, 1, 8);
}
}
}
imshow(output_win, drawImg);
return;
}
Code
moments(
InputArray array,//输入数据
bool binaryImage=false // 是否为二值图像
)
contourArea(
InputArray contour,//输入轮廓数据
bool oriented// 默认false、返回绝对值)
)
arcLength(
InputArray curve,//输入曲线数据
bool closed// 是否是封闭曲线)
)
c++
#include<opencv2\opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
Mat src, dst,gray_src;
int threshold_value = 80;
int threshold_max = 255;
RNG rng;
void Demo_Countours(int, void*);
string input_title = "input img";
string output_title = "output img";
int main(int argc, char * argv) {
src = imread("C:\\Users\\Administrator\\Pictures\\lab\\星球.jpg");
namedWindow(input_title, CV_WINDOW_AUTOSIZE);
namedWindow(output_title, CV_WINDOW_AUTOSIZE);
imshow(input_title, src);
//图像灰度化
cvtColor(src, gray_src, CV_BGR2GRAY);
//高斯模糊
GaussianBlur(gray_src, gray_src, Size(3, 3), 0, 0);
createTrackbar("control img", output_title, &threshold_value, threshold_max, Demo_Countours);
Demo_Countours(0, 0);
waitKey(0);
return 0;
}
void Demo_Countours(int, void*) {
Mat canny_out;
vector<vector<Point>> contours;
vector<Vec4i>hierachy;
//边缘检测
Canny(gray_src, canny_out, threshold_value, threshold_value * 2,3, false);
//轮廓发现
findContours(canny_out, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
vector<Moments> contours_moments(contours.size());
vector<Point2f> ccs(contours.size());
for (size_t i = 0; i < contours.size(); i++)
{
//计算矩
contours_moments[i] = moments(contours[i]);
//计算图像中心,获取中心坐标
ccs[i] = Point(static_cast<float>(contours_moments[i].m10 / contours_moments[i].m00), static_cast<float>(contours_moments[i].m01 / contours_moments[i].m00));
}
Mat drawImg;
src.copyTo(drawImg);
for (size_t i = 0; i < contours.size(); i++)
{
if (contours[i].size()<30)
{
continue;
}
//打印面积和长度
printf("contours %d area :%.2f and length :%.2f \n", i, contourArea(contours[i]), arcLength(contours[i], true));
//随机颜色
Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
//轮廓绘制
drawContours(drawImg, contours, i, color, 2, 8, hierachy, 0, Point(0, 0));
//画圆
circle(drawImg, ccs[i], 2, color, 2, 8);
}
imshow(output_title, drawImg);
}
测试一个点是否在给定的多边形内部,边缘或者外部
c++
pointPolygonTest(
InputArray contour,// 输入的轮廓
Point2f pt, // 测试点
bool measureDist // 是否返回距离值,如果是false,1表示在内面,0表示在边界上,-1表示在外部,true返回实际距离
)
返回数据是double类型
c++
#include<opencv2\opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
Mat src, dst,gray_src;
int threshold_value = 80;
int threshold_max = 255;
RNG rng;
string input_title = "input img";
string output_title = "output img";
const int r = 100;
int main(int argc, char * argv) {
src = Mat::zeros(r * 4, r * 4, CV_8UC1);
vector<Point2f> vert(6);
vert[0] = Point(3 * r / 2, static_cast<int>(1.34*r));
vert[1] = Point(1 * r, static_cast<int>(2 * r));
vert[2] = Point(3 * r / 2, static_cast<int>(2.886*r));
vert[3] = Point(5 * r / 2, static_cast<int>(2.886*r));
vert[4] = Point(3 * r, static_cast<int>(2 * r));
vert[5] = Point(5 * r / 2, static_cast<int>(1.34*r));
//画多边形
for (int i = 0; i < 6; i++)
{
line(src, vert[i], vert[(i + 1) % 6], Scalar(255), 8, LINE_8, 0);
}
vector<vector<Point>> contours;
vector<Vec4i> hierachy;
Mat csrc;
src.copyTo(csrc);
//轮廓发现
findContours(csrc, contours, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
Mat raw_dist = Mat::zeros(csrc.size(), CV_32FC1);
for (int row = 0; row < raw_dist.rows; row++)
{
for (int col = 0; col < raw_dist.cols; col++)
{
//点多边形测试
double dist = pointPolygonTest(contours[0], Point2f(static_cast<float>(col), static_cast<float>(row)), true);
raw_dist.at<float>(row, col) = static_cast<float>(dist);
}
}
double minValue, maxValue;
//归一化处理
minMaxLoc(raw_dist, &minValue, &maxValue, 0, 0, Mat());
Mat drawImg = Mat::zeros(src.size(), CV_8UC3);
for (int row = 0; row < drawImg.rows; row++)
{
for (int col = 0; col < drawImg.cols; col++)
{
float dist = raw_dist.at<float>(row, col);
if (dist > 0) {
drawImg.at<Vec3b>(row, col)[0] = (uchar)(abs(1.0 - (dist / maxValue)) * 255);
}
else if (dist < 0) {
drawImg.at<Vec3b>(row, col)[2] = (uchar)(abs(1.0- (dist / maxValue)) * 255);
}
else {
drawImg.at<Vec3b>(row, col)[0] = (uchar)(abs(255 - dist));
drawImg.at<Vec3b>(row, col)[1] = (uchar)(abs(255 - dist));
drawImg.at<Vec3b>(row, col)[2] = (uchar)(abs(255 - dist));
}
}
}
namedWindow(input_title, CV_WINDOW_AUTOSIZE);
namedWindow(output_title, CV_WINDOW_AUTOSIZE);
imshow(input_title, src);
imshow(output_title, drawImg);
waitKey(0);
return 0;
}
c++
cv::distanceTransform(InputArray src, OutputArray dst, OutputArray labels, int distanceType, int maskSize, int labelType=DIST_LABEL_CCOMP)
distanceType = DIST_L1/DIST_L2,
maskSize = 3x3,最新的支持5x5,推荐3x3、
labels离散维诺图输出
dst输出8位或者32位的浮点数,单一通道,大小与输入图像一致
cv::watershed(InputArray image, InputOutputArray markers)
c++
#include<opencv2\opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
Mat src, dst;
int threshold_value = 100;
int threshold_max = 255;
RNG rng;
string input_title = "input img";
string output_title = "output img";
int main(int argc, char * argv) {
src = imread("C:\\Users\\Administrator\\Pictures\\lab\\红桃.png");
namedWindow(input_title, CV_WINDOW_AUTOSIZE);
namedWindow(output_title, CV_WINDOW_AUTOSIZE);
//修改背景颜色
for (int row = 0; row < src.rows; row++)
{
for (int col = 0; col < src.cols; col++)
{
if (src.at<Vec3b>(row,col) == Vec3b(255,255,255))
{
src.at<Vec3b>(row, col)[0] = 0;
src.at<Vec3b>(row, col)[1] = 0;
src.at<Vec3b>(row, col)[2] = 0;
}
}
}
//膨胀(去除小黑点,噪点)
Mat structureElement = getStructuringElement(MORPH_RECT, Size(5, 5), Point(-1, -1));
dilate(src, src, structureElement, Point(-1, -1), 1);
//锐化图像,shape
Mat kernel = (Mat_<float>(3, 3) << 1, 1, 1, 1, -8, 1, 1, 1, 1);
Mat imgLaplance;
Mat shapenImg = src;
filter2D(src, imgLaplance, CV_32F, kernel, Point(-1, -1), 0, BORDER_DEFAULT);
src.convertTo(shapenImg, CV_32F);
Mat resultImg = shapenImg - imgLaplance;
resultImg.convertTo(resultImg, CV_8UC3);
imgLaplance.convertTo(imgLaplance, CV_8UC3);
//二值图像convert to binary
Mat binaryImg;
cvtColor(resultImg, resultImg, CV_BGR2GRAY);
threshold(resultImg, binaryImg, 40, 255, CV_THRESH_BINARY | THRESH_OTSU);
//距离变化
Mat distImg;
distanceTransform(binaryImg, distImg, DIST_L1, 3, 5);
normalize(distImg, distImg, 0, 1, NORM_MINMAX);
//距离变化之后再次二值化图像
threshold(distImg, distImg, 0.4, 1, THRESH_BINARY);
Mat kernel1 = Mat::zeros(13, 13, CV_8UC1);
//腐蚀
erode(distImg, distImg, kernel1);
//markers标记
Mat dist_8u;
distImg.convertTo(dist_8u, CV_8U);
vector<vector<Point>> contours;
findContours(dist_8u, contours, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
//create makers
Mat markers = Mat::zeros(src.size(), CV_32SC1);
for (size_t i = 0; i < contours.size(); i++)
{
drawContours(markers, contours, static_cast<int>(i), Scalar::all (static_cast<int>(i) + 1),-1);
}
circle(markers, Point(5, 5), 3, Scalar(255, 255, 255), -1);
//分水岭
watershed(src, markers);
Mat res = Mat::zeros(markers.size(), CV_8UC1);
markers.convertTo(res, CV_8UC1);
bitwise_not(res, res, Mat());
//生成随机颜色
vector<Vec3b> colors;
for (size_t i = 0; i < contours.size(); i++)
{
int r = rng.uniform(0, 255);
int g = rng.uniform(0, 255);
int b = rng.uniform(0, 255);
colors.push_back(Vec3b((uchar)b, (uchar)g, (uchar)r));
}
//填满颜色
dst = Mat::zeros(markers.size(), CV_8UC3);
for (int row = 0; row < src.rows; row++)
{
for (int col = 0; col < src.cols; col++)
{
int index = markers.at<int>(row, col);
if (index>0 && index<=static_cast<int>(contours.size()))
{
dst.at<Vec3b>(row, col) = colors[index - 1];
}
else {
dst.at<Vec3b>(row, col) = Vec3b(0, 0, 0);
}
}
}
imshow(input_title, src);
imshow(output_title, dst);
waitKey(0);
return 0;
}