近期
#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);
}
}