图像的阈值分割

使用C++、opencv对图像进行简单的阈值分割

对图像进行颜色的阈值分割,往往不知道阈值设置为多少合适,需要不断测试,针对此问题,设置了阈值的滑动条,从而可以通过滑动滑动条快速找到阈值。

最常见的阈值分割即为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 <opencv2\opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
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<src.rows;i++)
		for (int j = 0; j < src.cols; j++)
		{
			//大于阈值的点设为黑色
			if (src.at<Vec3b>(i, j)[2] > r)
			{
				dst.at<Vec3b>(i, j)[0] = 0;
				dst.at<Vec3b>(i, j)[1] = 0;
				dst.at<Vec3b>(i, j)[2] = 0;
			}
			if (src.at<Vec3b>(i, j)[1] > g)
			{
				dst.at<Vec3b>(i, j)[0] = 0;
				dst.at<Vec3b>(i, j)[1] = 0;
				dst.at<Vec3b>(i, j)[2] = 0;
			}
			if (src.at<Vec3b>(i, j)[0] > b)
			{
				dst.at<Vec3b>(i, j)[0] = 0;
				dst.at<Vec3b>(i, j)[1] = 0;
				dst.at<Vec3b>(i, j)[2] = 0;
			}
		}
	imshow("dst", dst);
}
void G_B_threshold()
{
	dst = src.clone();
	for (int i = 0; i<src.rows; i++)
		for (int j = 0; j < src.cols; j++)
		{
			if ((    abs(src.at<Vec3b>(i, j)[1] - src.at<Vec3b>(i, j)[2])	<	threshod_value	))
			{
				dst.at<Vec3b>(i, j)[0] = 0;
				dst.at<Vec3b>(i, j)[1] = 0;
				dst.at<Vec3b>(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<src.rows; i++)
		for (int j = 0; j < src.cols; j++)
		{
			if ((abs(2*src.at<Vec3b>(i, j)[1] - src.at<Vec3b>(i, j)[2] - src.at<Vec3b>(i, j)[0])	>	threshod_value))
			{
				dst.at<Vec3b>(i, j)[0] = 0;
				dst.at<Vec3b>(i, j)[1] = 0;
				dst.at<Vec3b>(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<Vec3b>(row, col)[1] / dst.at<Vec3b>(row, col)[2];
			a = a * 100;
			if (a < threshod_value)
			{
				dst.at<Vec3b>(row, col)[0] = 0;
				dst.at<Vec3b>(row, col)[1] = 0;
				dst.at<Vec3b>(row, col)[2] = 0;
			}
		}
	}
	imshow("dst", dst);
}

结果图:

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页