使用 Opencv 实现部分简单的halcon函数 auto_threshold

近期

#include "threshold.h"
#include <vector>

const double PI = 3.14159265358979323846;

void threshold(cv::Mat image, cv::Mat& region, int minGray, int maxGray) 
{
	if (image.channels() == 1) //单通道图像直接进行阈值化
	{ 
		cv::Mat dstImage1, dstImage2;
		cv::threshold(image, dstImage1, minGray, 255, cv::THRESH_BINARY);
		cv::threshold(image, dstImage2, maxGray, 255, cv::THRESH_BINARY_INV);
		cv::bitwise_and(dstImage1, dstImage2, region);
	}
	else 
	{ //多通道图像对每个通道进行阈值化后合并
		std::vector<cv::Mat> channels;
		cv::split(image, channels);
		for (int i = 0; i < channels.size(); i++)
		{
			cv::Mat dstImage1, dstImage2;
			cv::threshold(image, dstImage1, minGray, 255, cv::THRESH_BINARY);
			cv::threshold(image, dstImage2, maxGray, 255, cv::THRESH_BINARY_INV);
			cv::bitwise_and(dstImage1, dstImage2, channels[i]);
		}
		cv::merge(channels, region);
	}
}

void draw_hist(cv::Mat hist, cv::Mat& histImage, int rows, int cols)
{

	histImage = cv::Mat(rows, cols, CV_8U, cv::Scalar(0));
	//获取最大值和最小值
	double minValue = 0;
	double maxValue = 0;
	cv::minMaxLoc(hist, &minValue, &maxValue, 0, 0);  //  在cv中用的是cvGetMinMaxHistValue
	int hpt = cv::saturate_cast<int>(0.9 * hist.rows); //saturate_cast函数的作用即是:当运算完之后,结果为负,则转为0,结果超出255,则为255。

	for (int i = 0; i < 256; i++)
	{
		float binValue = hist.at<float>(i);           //   注意hist中是float类型   
		int realValue = cv::saturate_cast<int>(binValue * hpt / maxValue);//拉伸到0-max
		line(histImage, cv::Point(i, hist.rows - 1), cv::Point(i, hist.rows - realValue), cv::Scalar(255));
	}
	cv::imshow("一维直方图", histImage);
	cv::waitKey(0);

}

void get_peak_and_trough(cv::Mat hist, std::vector<int>& peak, std::vector<int>& trough) 
{
	for (int i = 1; i < hist.rows - 1; i++)
	{
		float x1 = hist.at<float>(i, 0) - hist.at<float>(i - 1, 0);
		float x2 = hist.at<float>(i + 1, 0) - hist.at<float>(i, 0);
		if (x1 > 0 && x2 < 0) 
		{
			peak.push_back(i);
		}
		else if (x2 > 0 && x1 < 0) 
		{
			trough.push_back(i);
		}
	}
}

void auto_threshold(cv::Mat image, cv::Mat& region, float sigma) 
{
	cv::Mat gray;
	if (image.channels() > 1)
	{
		cvtColor(image, gray, cv::COLOR_BGR2GRAY);
	}
	else 
	{
		gray = image.clone();
	}
	//设定直方图相关参数
	int histBinNum = 256;
	float range[] = { 0, 255 };
	const float* histRange[] = { range };
	bool uniform = true;
	bool accumulate = false;

	//获取直方图矩阵
	cv::Mat hist;
	calcHist(&gray, 1, 0, cv::Mat(), hist, 1, &histBinNum, histRange, uniform, accumulate);

	//  //直方图图像
	//  cv::Mat histImage;
	//  draw_hist(hist, histImage, image.rows, image.cols);

	//一维高斯滤波
	int filterSize = round(2 * 3 * sigma);// ±3sigma区间大小
	if (filterSize % 2 == 0) 
	{
		filterSize += 1;
	}
	int radius = (filterSize - 1) / 2;
	std::cout << filterSize << std::endl;
	cv::Mat filter(filterSize, 1, CV_32FC1);
	for (int i = 0; i < filterSize; i++) 
	{
		float x = i - radius;
		filter.at<float>(i, 0) = exp(-(x*x) / (2 * sigma*sigma)) / (sqrt(2 * PI)*sigma);
	}
	cv::Mat dstHist, dstHistImage;
	cv::filter2D(hist, dstHist, CV_32FC1, filter);
	draw_hist(dstHist, dstHistImage, image.rows, image.cols);

	std::vector<int> peak, trough;
	get_peak_and_trough(dstHist, peak, trough);
	if (trough.size() == 0) //直方图为单峰的图像,使用Triangle分割法
	{
		cv::threshold(image, region, 0, 255, CV_THRESH_TRIANGLE);
	}
	else if (trough.size() == 1) //只有一个波谷,即为双峰图像,以波谷为分割阈值作分割
	{
		cv::threshold(image, region, trough[0], 255, CV_THRESH_BINARY);
	}
	else //多个波谷,即为多峰图像,每两个峰谷作一次分割
	{
		std::vector<cv::Mat> regions;
		for (int i = 0; i < trough.size() - 1; i++) {
			int minGray = trough[i];
			int maxGray = trough[i + 1];
			cv::Mat _region;
			threshold(image, _region, minGray, maxGray);
			regions.push_back(_region);
			cv::imshow("_region", _region);
			cv::waitKey(0);
		}
	}
}

void reduce_domain(cv::Mat image, cv::Mat region, cv::Mat& imageReduce)
{
	if (image.channels()==1)
	{
		cv::bitwise_and(image, region, imageReduce);
	}
	else
	{
		std::vector<cv::Mat> channels;
		cv::split(image, channels);
		for each (cv::Mat channel in channels)
		{
			cv::bitwise_and(channel, region, channel);
		}
		cv::merge(channels, imageReduce);
	}
}

 

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当然,这是一个使用OpenCV的C++实现的boundingRect的使用示例: ```cpp #include <opencv2/opencv.hpp> #include <iostream> int main() { // 读取图像 cv::Mat image = cv::imread("image.jpg"); // 转换为灰度图像 cv::Mat gray; cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY); // 二值化图像 cv::Mat binary; cv::threshold(gray, binary, 128, 255, cv::THRESH_BINARY); // 寻找轮廓 std::vector<std::vector<cv::Point>> contours; cv::findContours(binary, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE); // 遍历每个轮廓,获取boundingRect for (const auto& contour : contours) { // 计算boundingRect cv::Rect boundingRect = cv::boundingRect(contour); // 在原始图像上绘制boundingRect cv::rectangle(image, boundingRect, cv::Scalar(0, 255, 0), 2); } // 显示结果 cv::imshow("Bounding Rect", image); cv::waitKey(0); return 0; } ``` 这个示例演示了如何使用OpenCV的`boundingRect`函数来计算轮廓的边界矩形,并在原始图像上绘制出找到的边界矩形。首先,加载图像并将其转换为灰度图像。然后,使用阈值化将灰度图像转换为二值图像。接下来,使用`findContours`函数找到二值图像中的轮廓。然后,遍历每个轮廓,使用`boundingRect`函数计算该轮廓的边界矩形,并在原始图像上绘制出边界矩形。最后,显示带有边界矩形的图像。 请注意,您需要将代码中的"image.jpg"替换为您自己的图像路径。此外,确保您已经正确安装和配置了OpenCV库。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值