本文主要介绍了适合当图像的直方图具有明显单峰特征时使用,结合了三角法的原理而设计的图像分割方法,感兴趣的小伙伴可以了解一下
6)右侧同理,连接峰值(maxidx,max)和(0,0)点,公式ABC如代码所示。
else {
float A = float(-max);
float B = float(maxidx);
float C = 0.0f;
for (int i = 0; i < maxidx; ++i)
{
float x0 = float(i);
float y0 = hist.at<float>(0, i);
float d = abs(A * x0 + B * y0 + C) / std::sqrt(A * A + B * B);
if (d > maxd)
{
maxd = d;
maxdidx = i;
}
}
}
7)二值化,完成。
result.setTo(255, src > maxdidx);
idx = maxdidx;
return result;
功能函数
// 单峰三角阈值法
cv::Mat Thresh_Unimodal(cv::Mat &src, int& idx)
{
cv::Mat result = cv::Mat::zeros(src.size(), CV_8UC1);
// 统计直方图
cv::Mat hist = cv::Mat::zeros(1, 256, CV_32FC1);
for (int i = 0; i < src.rows; ++i)
{
for (int j = 0; j < src.cols; ++j)
{
hist.at<float>(0, src.at<uchar>(i, j))++;
}
}
hist.at<float>(0, 255) = 0;
hist.at<float>(0, 0) = 0;
// 搜索最大值位置
float max = 0;
int maxidx = 0;
for (int i = 0; i < 256; ++i)
{
if (hist.at<float>(0, i) > max)
{
max = hist.at<float>(0, i);
maxidx = i;
}
}
// 判断最大点在哪一侧,true为左侧,false为右侧
bool lr = maxidx < 127;
float maxd = 0;
int maxdidx = 0;
// 假设在左侧
if (lr)
{
float A = float(-max);
float B = float(maxidx - 255);
float C = float(max * 255);
for (int i = maxidx + 1; i < 256; ++i)
{
float x0 = float(i);
float y0 = hist.at<float>(0, i);
float d = abs(A * x0 + B * y0 + C) / std::sqrt(A * A + B * B);
if (d > maxd)
{
maxd = d;
maxdidx = i;
}
}
}
// 假设在右侧
else {
float A = float(-max);
float B = float(maxidx);
float C = 0.0f;
for (int i = 0; i < maxidx; ++i)
{
float x0 = float(i);
float y0 = hist.at<float>(0, i);
float d = abs(A * x0 + B * y0 + C) / std::sqrt(A * A + B * B);
if (d > maxd)
{
maxd = d;
maxdidx = i;
}
}
}
// 二值化
result.setTo(255, src > maxdidx);
idx = maxdidx;
return result;
}
C++测试代码
#include <iostream>
#include <time.h>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
cv::Mat DrawHistImg(cv::Mat &hist);
cv::Mat Thresh_Unimodal(cv::Mat &src, int& idx);
int main()
{
cv::Mat src = imread("test.jpg", 0);
// 绘制均衡化后直方图
cv::Mat hrI = DrawHistImg(src);
// 单峰三角阈值法
int thresh;
cv::Mat result = Thresh_Unimodal(src, thresh);
cout << " thresh: " << thresh << endl;
imshow("original", src);
imshow("hist", hrI);
imshow("result", result);
waitKey(0);
return 0;
}
// 绘制简易直方图
cv::Mat DrawHistImg(cv::Mat &src)
{
cv::Mat hist = cv::Mat::zeros(1, 256, CV_32FC1);
for (int i = 0; i < src.rows; ++i)
{
for (int j = 0; j < src.cols; ++j)
{
hist.at<float>(0, src.at <uchar>(i, j))++;
}
}
cv::Mat histImage = cv::Mat::zeros(540, 1020, CV_8UC1);
const int bins = 255;
double maxValue;
cv::Point2i maxLoc;
cv::minMaxLoc(hist, 0, &maxValue, 0, &maxLoc);
int scale = 4;
int histHeight = 540;
for (int i = 0; i < bins; i++)
{
float binValue = (hist.at<float>(i));
int height = cvRound(binValue * histHeight / maxValue);
cv::rectangle(histImage, cv::Point(i * scale, histHeight),
cv::Point((i + 1) * scale - 1, histHeight - height), cv::Scalar(255), -1);
}
return histImage;
}
// 单峰三角阈值法
cv::Mat Thresh_Unimodal(cv::Mat &src, int& idx)
{
cv::Mat result = cv::Mat::zeros(src.size(), CV_8UC1);
// 统计直方图
cv::Mat hist = cv::Mat::zeros(1, 256, CV_32FC1);
for (int i = 0; i < src.rows; ++i)
{
for (int j = 0; j < src.cols; ++j)
{
hist.at<float>(0, src.at<uchar>(i, j))++;
}
}
hist.at<float>(0, 255) = 0;
hist.at<float>(0, 0) = 0;
// 搜索最大值位置
float max = 0;
int maxidx = 0;
for (int i = 0; i < 256; ++i)
{
if (hist.at<float>(0, i) > max)
{
max = hist.at<float>(0, i);
maxidx = i;
}
}
// 判断最大点在哪一侧,true为左侧,false为右侧
bool lr = maxidx < 127;
float maxd = 0;
int maxdidx = 0;
// 假设在左侧
if (lr)
{
float A = float(-max);
float B = float(maxidx - 255);
float C = float(max * 255);
for (int i = maxidx + 1; i < 256; ++i)
{
float x0 = float(i);
float y0 = hist.at<float>(0, i);
float d = abs(A * x0 + B * y0 + C) / std::sqrt(A * A + B * B);
if (d > maxd)
{
maxd = d;
maxdidx = i;
}
}
}
// 假设在右侧
else {
float A = float(-max);
float B = float(maxidx);
float C = 0.0f;
for (int i = 0; i < maxidx; ++i)
{
float x0 = float(i);
float y0 = hist.at<float>(0, i);
float d = abs(A * x0 + B * y0 + C) / std::sqrt(A * A + B * B);
if (d > maxd)
{
maxd = d;
maxdidx = i;
}
}
}
// 二值化
result.setTo(255, src > maxdidx);
idx = maxdidx;
return result;
}
测试效果
图1 原图灰度图
图2 直方图
图3 阈值图
图4 阈值结果
通过imagewatch插件可以观察阈值203是不是在距离最远的位置,答案是肯定的。
如果函数有什么可以改进完善的地方,非常欢迎大家指出,一同进步何乐而不为呢~
以上就是C++ OpenCV单峰三角阈值法Thresh_Unimodal详解的详细内容,更多关于C++ OpenCV单峰三角阈值法的资料请关注编程学习网其它相关文章!
沃梦达教程
本文标题为:C++ OpenCV单峰三角阈值法Thresh_Unimodal详解


猜你喜欢
- 详解C语言中sizeof如何在自定义函数中正常工作 2023-04-09
- 我应该为我的项目使用相对包含路径,还是将包含目录放在包含路径上? 2022-10-30
- Easyx实现扫雷游戏 2023-02-06
- C语言手把手带你掌握带头双向循环链表 2023-04-03
- ubuntu下C/C++获取剩余内存 2023-09-18
- C语言qsort()函数的使用方法详解 2023-04-26
- Qt计时器使用方法详解 2023-05-30
- C++ 数据结构超详细讲解顺序表 2023-03-25
- c++ const 成员函数,返回一个 const 指针.但是返回的指针是什么类型的 const? 2022-10-11
- C语言详解float类型在内存中的存储方式 2023-03-27