图像处理:轮廓——点多边形测试 OpenCV v4.8.0

上一个教程图像矩

下一个教程使用距离变换和分水岭算法进行图像分割

原作者Ana Huamán
兼容性OpenCV >= 3.0

目标

在本教程中,您将学习如何

代码

C++
本教程代码如下所示。您也可以从此处下载

#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;
int main( void )
{
 const int r = 100;
 Mat src = Mat::zeros( Size( 4*r, 4*r ), CV_8U );
 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) );
 for( int i = 0; i < 6; i++ )
 {
 line( src, vert[i], vert[(i+1)%6], Scalar( 255 ), 3 );
 }
 vector<vector<Point> > contours;
 findContours( src, contours, RETR_TREE, CHAIN_APPROX_SIMPLE);
 Mat raw_dist( src.size(), CV_32F );
 for( int i = 0; i < src.rows; i++ )
 {
 for( int j = 0; j < src.cols; j++ )
 {
 raw_dist.at<float>(i,j) = (float)pointPolygonTest( contours[0], Point2f((float)j, (float)i), true );
 }
 }
 double minVal, maxVal;
 Point maxDistPt; // 内切圆中心
 minMaxLoc(raw_dist, &minVal, &maxVal, NULL, &maxDistPt);
 minVal = abs(minVal);
 maxVal = abs(maxVal);
 Mat drawing = Mat::zeros( src.size(), CV_8UC3 );
 for( int i = 0; i < src.rows; i++ )
 {
 for( int j = 0; j < src.cols; j++ )
 {
 if( raw_dist.at<float>(i,j) < 0 )
 {
 drawing.at<Vec3b>(i,j)[0] = (uchar)(255 - abs(raw_dist.at<float>(i,j)) * 255 / minVal);
 }
 else if( raw_dist.at<float>(i,j) > 0 )
 {
 drawing.at<Vec3b>(i,j)[2] = (uchar)(255 - raw_dist.at<float>(i,j) * 255 / maxVal);
 }
 else
 {
 drawing.at<Vec3b>(i,j)[0] = 255;
 drawing.at<Vec3b>(i,j)[1] = 255;
 drawing.at<Vec3b>(i,j)[2] = 255;
 }
 }
 }
 circle(drawing, maxDistPt, (int)maxVal, Scalar(255,255,255));
 imshow( "Source", src );
 imshow( "Distance and inscribed circle", drawing );
 waitKey();
 return 0;
}

Java
本教程代码如下所示。您也可以从此处下载

import java.util.ArrayList;
import java.util.List;
import org.opencv.core.Core;
import org.opencv.core.Core.MinMaxLocResult;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfPoint;
import org.opencv.core.MatOfPoint2f;
import org.opencv.core.Point;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.highgui.HighGui;
import org.opencv.imgproc.Imgproc;
class PointPolygonTest {
 public void run() {
 int r = 100;
 Mat src = Mat.zeros(new Size(4 * r, 4 * r), CvType.CV_8U);
 List<Point> vert = new ArrayList<>(6);
 vert.add(new Point(3 * r / 2, 1.34 * r));
 vert.add(new Point(1 * r, 2 * r));
 vert.add(new Point(3 * r / 2, 2.866 * r));
 vert.add(new Point(5 * r / 2, 2.866 * r));
 vert.add(new Point(3 * r, 2 * r));
 vert.add(new Point(5 * r / 2, 1.34 * r));
 for (int i = 0; i < 6; i++) {
 Imgproc.line(src, vert.get(i), vert.get((i + 1) % 6), new Scalar(255), 3);
 }
 List<MatOfPoint> contours = new ArrayList<>();
 Mat hierarchy = new Mat();
 Imgproc.findContours(src, contours, hierarchy, Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_SIMPLE);
 Mat rawDist = new Mat(src.size(), CvType.CV_32F);
 float[] rawDistData = new float[(int) (rawDist.total() * rawDist.channels())];
 for (int i = 0; i < src.rows(); i++) {
 for (int j = 0; j < src.cols(); j++) {
 rawDistData[i * src.cols() + j] = (float) Imgproc
 .pointPolygonTest(new MatOfPoint2f(contours.get(0).toArray()), new Point(j, i), true);
 }
 }
 rawDist.put(0, 0, rawDistData);
 MinMaxLocResult res = Core.minMaxLoc(rawDist);
 double minVal = Math.abs(res.minVal);
 double maxVal = Math.abs(res.maxVal);
 Mat drawing = Mat.zeros(src.size(), CvType.CV_8UC3);
 byte[] drawingData = new byte[(int) (drawing.total() * drawing.channels())];
 for (int i = 0; i < src.rows(); i++) {
 for (int j = 0; j < src.cols(); j++) {
 if (rawDistData[i * src.cols() + j] < 0) {
 drawingData[(i * src.cols() + j) * 3] =
 (byte) (255 - Math.abs(rawDistData[i * src.cols() + j]) * 255 / minVal);
 } else if (rawDistData[i * src.cols() + j] > 0) {
 drawingData[(i * src.cols() + j) * 3 + 2] =
 (byte) (255 - rawDistData[i * src.cols() + j] * 255 / maxVal);
 } else {
 drawingData[(i * src.cols() + j) * 3] = (byte) 255;
 drawingData[(i * src.cols() + j) * 3 + 1] = (byte) 255;
 drawingData[(i * src.cols() + j) * 3 + 2] = (byte) 255;
 }
 }
 }
 drawing.put(0, 0, drawingData);
 Imgproc.circle(drawing, res.maxLoc, (int)res.maxVal, new Scalar(255, 255, 255), 2, 8, 0);
 HighGui.imshow("Source", src);
 HighGui.imshow("Distance and inscribed circle", drawing);
 HighGui.waitKey();
 System.exit(0);
 }
}
public class PointPolygonTestDemo {
 public static void main(String[] args) {
 // 加载本地 OpenCV 库
 System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
 new PointPolygonTest().run();
 }
}

Python
本教程代码如下所示。您也可以从此处下载

from __future__ import print_function
from __future__ import division
import cv2 as cv
import numpy as np
# 创建图像
r = 100
src = np.zeros((4*r, 4*r), dtype=np.uint8)
# 创建点序列,绘制等高线
vert = [None]*6
vert[0] = (3*r//2, int(1.34*r))
vert[1] = (1*r, 2*r)
vert[2] = (3*r//2, int(2.866*r))
vert[3] = (5*r//2, int(2.866*r))
vert[4] = (3*r, 2*r)
vert[5] = (5*r//2, int(1.34*r))
# 在 src 中绘制
for i in range(6):
 cv.line(src, vert[i], vert[(i+1)%6], ( 255 ), 3)
# 获取轮廓
contours, _ = cv.findContours(src, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
# 计算与等高线的距离
raw_dist = np.empty(src.shape, dtype=np.float32)
for i in range(src.shape[0])for j in range(src.shape[1]):
 raw_dist[i,j] = cv.pointPolygonTest(contours[0], (j,i), True)
minVal, maxVal, _, maxDistPt = cv.minMaxLoc(raw_dist)
minVal = abs(minVal)
maxVal = abs(maxVal)
# 用图形描述距离
drawing = np.zeros((src.shape[0], src.shape[1], 3), dtype=np.uint8)
for i in range(src.shape[0]):
 for j in range(src.shape[1]):
 if raw_dist[i,j] < 0:
 drawing[i,j,0] = 255 - abs(raw_dist[i,j]) * 255 / minVal
 elif raw_dist[i,j] > 0:
 drawing[i,j,2] = 255 - raw_dist[i,j] * 255 / maxVal
 else:
 drawing[i,j,0] = 255
 drawing[i,j,1] = 255
 drawing[i,j,2] = 255
cv.circle(drawing,maxDistPt, int(maxVal),(255,255,255), 1, cv.LINE_8, 0)
cv.imshow('Source', src)
cv.imshow('Distance and inscribed circle', drawing)
cv.waitKey()

结果

在这里

在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值