OpenCV-图像处理(32、点多边形测试)

版权声明:本文由 Micheal 超 博客 创作,未经博主允许不得转载。 https://blog.csdn.net/qq_42887760/article/details/86586568

概念介绍 - 点多边形测试

  • 测试一个点是否在给定的多边形内部,边缘或者外部
    在这里插入图片描述

API介绍 cv::pointPolygonTest

double pointPolygonTest( //返回数据是类型
InputArray contour,// 输入的轮廓
Point2f pt, // 测试点
bool measureDist // 是否返回距离值,如果是false,1表示在内面,0表示在边界上,-1表示在外部,true返回实际距离
)

演示代码-步骤

  1. 构建一张400x400大小的图片, Mat::Zero(400, 400, CV_8UC1)
  2. 画上一个六边形的闭合区域line
  3. 发现轮廓
  4. 对图像中所有像素点做点 多边形测试,得到距离,归一化后显示。

程序代码:

#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
using namespace cv;
using namespace std;
 
int main( int argc, char** argv ){
	// 绘制一张6边形的图像    
	const int r = 100;
	Mat 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, 2 * r);
	vert[2] = Point(3 * r / 2, static_cast<int>(2.866*r));   
	vert[3] = Point(5 * r / 2, static_cast<int>(2.866*r));
	vert[4] = Point(3 * r, 2 * r);   
	vert[5] = Point(5 * r / 2, static_cast<int>(1.34*r));
 
	// 在src内部绘制,并显示出来
	for (int i = 0; i < 6; i++) {
		line(src, vert[i], vert[(i + 1) % 6], Scalar(255), 3, 8, 0);
	}

	char* source_window = "Source";
	namedWindow( source_window, CV_WINDOW_AUTOSIZE );
	imshow( source_window, src );

	// 得到轮廓
	vector<vector<Point> > contours; 
	vector<Vec4i> hierarchy;
	//也可以写成:src.copyTo(src_copy);
	Mat src_copy = src.clone();// findContours 会改动输入图像 src 中元素的值,所以这里需要完全复制一份src
	//发现轮廓
	findContours( src_copy, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);
 
	// 计算到轮廓的距离,也可以写成:Mat raw_dist = Mat::zeros(src_copy.size(), CV_32FC1);
	Mat raw_dist( src.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);
			//raw_dist.at<float>(row,col) = pointPolygonTest( contours[0], Point2f(i,j), true ); 
		}
	}

	//绘制原图轮廓
    Mat dst = Mat::zeros(src.size(), CV_8UC3);
    for (size_t i = 0; i < contours.size(); i++) {
        drawContours(dst, contours, i, Scalar(0, i == 0 ? 0 : 255, 255), 2, 8, hierarchy, 0, Point(0, 0));
    }
    imshow("foundContours33", dst);


	// 绘制距离色差图,类似于 距离变换
	double minVal, maxVal;
	minMaxLoc( raw_dist, &minVal, &maxVal, 0, 0, Mat() );//获取最大最小距离,方便颜色归一化到255之间
	minVal = abs(minVal); maxVal = abs(maxVal);
 
	// 图形化的显示距离
	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 / maxVal)) * 255);//蓝
            }
            else if (dist < 0) { // 轮廓外部,越远离轮廓越黑
                drawImg.at<Vec3b>(row, col)[2] = (uchar)(abs(1.0 - (dist / minVal)) * 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( "Distance", CV_WINDOW_AUTOSIZE );
	imshow( "Distance", drawImg );

	/*  //与上面“图形化的显示距离”代码的功能相同,只是不同的显示方法而已,可以忽略
	// 图形化的显示距离
	Mat drawing = Mat::zeros( src.size(), CV_8UC3 );//用彩色图反差距离

	for( int j = 0; j < src.rows; j++ ){ 
		for( int i = 0; i < src.cols; i++ ){
			if( raw_dist.at<float>(j,i) < 0 ){ 
				drawing.at<Vec3b>(j,i)[0] = 255 - (int) abs(raw_dist.at<float>(j,i))*255/minVal; 
			}else if( raw_dist.at<float>(j,i) > 0 ){ 
				drawing.at<Vec3b>(j,i)[2] = 255 - (int) raw_dist.at<float>(j,i)*255/maxVal; 
			}else{ 
				drawing.at<Vec3b>(j,i)[0] = 255; drawing.at<Vec3b>(j,i)[1] = 255; drawing.at<Vec3b>(j,i)[2] = 255; 
			}
		}
	}
	// 创建窗口显示结果
	namedWindow( "drawing", CV_WINDOW_AUTOSIZE );
	imshow( "drawing", drawing );
	*/

	waitKey(0);
	return(0);
}

运行截图:

在这里插入图片描述
在这里插入图片描述

参考博客

  1. https://blog.csdn.net/huanghuangjin/article/details/81191011
  2. https://blog.csdn.net/LYKymy/article/details/83210442

猜你喜欢

转载自blog.csdn.net/qq_42887760/article/details/86586568