对图像进行颜色的阈值分割,往往不知道阈值设置为多少合适,需要不断测试,针对此问题,设置了阈值的滑动条,从而可以通过滑动滑动条快速找到阈值。
最常见的阈值分割即为R、G、B的阈值分割,即判断像素点的R、G、B值是否大于或小于某一阈值,满足条件的点就保留或删除。
本代码阈值分割的算法是直接按行按列依次遍历图像每个像素点,判断像素点的值是否满足分割条件,满足即将该点设置为黑色来达到分割的效果。代码为阈值、 R、G、B、和模式都设置了滑动条,其中模式有4种:
0----RGB R、G、B值大于阈值的点设为黑色
1----|G-R| G-R值的绝对值小于threshod_value的点设为黑色
2----|2G-R-B| 2G-R-B值的绝对值大于threshod_value的点设为黑色
3----G/R G/R值小于threshod_value的点设为黑色
创建滑动条的API:
int createTrackbar(const string& trackbarname, const string& winname, int* value, int count, TrackbarCallback onChange=0, void* userdata=0)
第一个参数,const string&类型的trackbarname,轨迹条的名字,用来代表我们创建的轨迹条。
第二个参数,const string&类型的winname,窗口的名字,表示这个轨迹条会依附到哪个窗口上,即对应named Window创建窗口时填的某一个窗口。
第三个参数,int*类型的value,一个指向整型的指针,表示滑块的位置。在创建时,滑块的初始位置就是该变量当前的值。
第四个参数,int类型的count,表示滑块可以达到的最大位置的值。滑块最小位置的值始终为0。
第五个参数,Trackbar Callback类型的on Change,它有默认值0。这是一个指向回调函数的指针,每次滑块位置改变时,这个函数都会进行回调。并且这个函数的原型必须为void XXXX(int,void*),其中第一个参数是轨迹条的位置,第二个参数是用户数据(看下面的第六个参数)。如果回调是NULL指针,则表示没有回调函数的调用,仅第三个参数value有变化。
第六个参数,void*类型的userdata,也有默认值0。这个参数是用户传给回调函数的数据,用来处理轨迹条事件。如果使用的第三个参数value实参是全局变量的话,完全可以不去管这个userdata参数。
代码实现:
#include "stdafx.h"
#include
#include
#include
#include
#include
using namespace cv;
Mat src,dst;
//滑动条相关全局变量
int mode = 0;
int r = 255, g = 255, b = 255;
int threshod_value = 70;
//滑动条回调函数声明
void on_mode(int, void*);
void on_threshold(int, void*);
//阈值处理函数声明
void RGB_threshold();
void G_B_threshold();
void G_B_R_threshold();
void G_R_threshold();
//帮助文本
void show_help()
{
std::cout << "---------help---------" << std::endl;
std::cout << "mode:" << std::endl;
std::cout << "0----RGB R、G、B值大于阈值的点设为黑色" << std::endl;
std::cout << "1----|G-R| G-R值的绝对值小于threshod_value的点设为黑色" << std::endl;
std::cout << "2----|2G-R-B| 2G-R-B值的绝对值大于threshod_value的点设为黑色" << std::endl;
std::cout << "3----G/R G/R值小于threshod_value的点设为黑色" << std::endl;
}
int main()
{
system("color 02");
show_help();
//读取图像
src = imread("D:\\哀.jpg");
namedWindow("src", WINDOW_NORMAL);
imshow("src", src);
namedWindow("dst", WINDOW_NORMAL);
//创建滑动条
createTrackbar("mode", "src", &mode, 4, on_mode);
on_mode(0, 0);
createTrackbar("R", "src", &r, 255, on_threshold);
on_threshold(0, 0);
createTrackbar("G", "src", &g, 255, on_threshold);
on_threshold(0, 0);
createTrackbar("B", "src", &b, 255, on_threshold);
on_threshold(0, 0);
createTrackbar("thre_val", "src", &threshod_value, 255, on_threshold);
on_threshold(0, 0);
waitKey();
return 0;
}
void on_mode(int, void*)
{
}
void on_threshold(int, void*)
{
switch (mode)
{
case 0:
RGB_threshold();
break;
case 1:
G_B_threshold();
break;
case 2:
G_B_R_threshold();
break;
case 3:
G_R_threshold();
break;
}
}
void RGB_threshold()
{
//复制源图到目标图像
dst = src.clone();
//遍历图像每个像素点
for(int i=0;i(i, j)[2] > r)
{
dst.at(i, j)[0] = 0;
dst.at(i, j)[1] = 0;
dst.at(i, j)[2] = 0;
}
if (src.at(i, j)[1] > g)
{
dst.at(i, j)[0] = 0;
dst.at(i, j)[1] = 0;
dst.at(i, j)[2] = 0;
}
if (src.at(i, j)[0] > b)
{
dst.at(i, j)[0] = 0;
dst.at(i, j)[1] = 0;
dst.at(i, j)[2] = 0;
}
}
imshow("dst", dst);
}
void G_B_threshold()
{
dst = src.clone();
for (int i = 0; i(i, j)[1] - src.at(i, j)[2]) < threshod_value ))
{
dst.at(i, j)[0] = 0;
dst.at(i, j)[1] = 0;
dst.at(i, j)[2] = 0;
}
}
//开操作
//Mat element = getStructuringElement(MORPH_RECT, Size(3, 3));
//morphologyEx(dst, dst, MORPH_OPEN, element);
imshow("dst", dst);
}
void G_B_R_threshold()
{
dst = src.clone();
for (int i = 0; i(i, j)[1] - src.at(i, j)[2] - src.at(i, j)[0]) > threshod_value))
{
dst.at(i, j)[0] = 0;
dst.at(i, j)[1] = 0;
dst.at(i, j)[2] = 0;
}
}
//腐蚀操作
//Mat element = getStructuringElement(MORPH_RECT, Size(3, 3));
//morphologyEx(dst, dst, MORPH_ERODE, element);
imshow("dst", dst);
}
void G_R_threshold()
{
dst = src.clone();
int height = dst.rows;
int width = dst.cols;
for (int row = 0; row < height; row++)
{
for (int col = 0; col < width; col++)
{
double a = (double)dst.at(row, col)[1] / dst.at(row, col)[2];
a = a * 100;
if (a < threshod_value)
{
dst.at(row, col)[0] = 0;
dst.at(row, col)[1] = 0;
dst.at(row, col)[2] = 0;
}
}
}
imshow("dst", dst);
}
结果图: