基础知识
基本方法
OpenCV中已经实现了常用的阈值处理方式,可以通过关键字进行选择(开头均以 THRESH 表示):
阈值 thresh , 值 maxval 对应函数 threshold 中的 maxval.
1. THRESH_BINARY
大于thresh的置为 maxval , 小于 thresh 的置为 0;
dst
(
x
,
y
)
=
{
maxval
if
src
(
x
,
y
)
>
thresh
0
otherwise
\operatorname{dst}(x, y)=\left\{\begin{array}{ll} \text { maxval } & \text { if } \operatorname{src}(x, y)>\text { thresh } \\ 0 & \text { otherwise } \end{array}\right.
dst(x,y)={ maxval 0 if src(x,y)> thresh otherwise
2. THRESH_BINARY_INV
对上面取反
dst
(
x
,
y
)
=
{
0
if
src
(
x
,
y
)
>
thresh
maxval
otherwise
\operatorname{dst}(x, y)=\left\{\begin{array}{ll} 0 & \text { if } \operatorname{src}(x, y)>\text { thresh } \\ \text { maxval } & \text { otherwise } \end{array}\right.
dst(x,y)={0 maxval if src(x,y)> thresh otherwise
3. THRESH_TRUNC
大于阈值thresh的取 thresh,小于阈值的不变
dst
(
x
,
y
)
=
{
threshold
if
src
(
x
,
y
)
>
thresh
src
(
x
,
y
)
otherwise
\operatorname{dst}(x, y)=\left\{\begin{array}{ll} \text { threshold } & \text { if } \operatorname{src}(x, y)>\text { thresh } \\ \operatorname{src}(x, y) & \text { otherwise } \end{array}\right.
dst(x,y)={ threshold src(x,y) if src(x,y)> thresh otherwise
4. THRESH_TOZERO
大于阈值thresh的取 当前值 src,小于阈值的置0
dst
(
x
,
y
)
=
{
src
(
x
,
y
)
if
src
(
x
,
y
)
>
thresh
0
otherwise
\operatorname{dst}(x, y)=\left\{\begin{array}{ll} \operatorname{src}(x, y) & \text { if } \operatorname{src}(x, y)>\text { thresh } \\ 0 & \text { otherwise } \end{array}\right.
dst(x,y)={src(x,y)0 if src(x,y)> thresh otherwise
5. THRESH_TOZERO_INV
对上面取反
dst
(
x
,
y
)
=
{
0
if
src
(
x
,
y
)
>
thresh
src
(
x
,
y
)
otherwise
\operatorname{dst}(x, y)=\left\{\begin{array}{ll} 0 & \text { if } \operatorname{src}(x, y)>\text { thresh } \\ \operatorname{src}(x, y) & \text { otherwise } \end{array}\right.
dst(x,y)={0src(x,y) if src(x,y)> thresh otherwise
图形表示
OTSU 大津法
适用于双峰阈值
将图像中的像素分为前景像素与背景像素,当前景像素集合与背景像素集合之间的类间方差最大时所对应的阈值,即为该图像的最优阈值。
通俗理解为: 图像直方图中两个波峰(前景像素、背景像素)之间的最低谷所对应的像素值。
TRIANGLE 算法
适用于单峰阈值
基于直方图数据,阈值最高点与最低点构成一条直线,求直方图上的每一点到该直线的距离,最大的距离即为所选取的阈值。
自适应阈值方法
以上都是固定阈值,即全局阈值,缺少对细节的把握。而自适应阈值,又称为局部阈值,对于每个点及其周围区域的像素值计算阈值,以此进行二值化。这样可以较好的效果,但是计算量偏大。
OpenCV中有两种计算方式,一个是 基于平均灰度和基于高斯函数。
函数原型为:
其中 maxValue与全局阈值中 maxval 含义相同,大于/小于 阈值将其置为 maxValue。blockSize指计算阈值的区域大小,大的区域计算速度快,小的区域细节处理较好,需要根据实际情况进行取舍。上述方式计算出来的阈值减去C即为所采用的阈值。C一般为正值。
实验验证
为直观的显示阈值处理的结果,采用创建滚动条的方式(createTrankbar函数)进行演示。
这里使用函数中的data传递数据,避免声明一大堆全局变量。
程序
main.cpp
//
// Created by zzl on 2021/1/11.
//
// 对圆锥体进行单目测距
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
// OpenCV
#include "opencv2/core.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/calib3d.hpp"
using namespace std;
using namespace cv;
enum Threshold {
BINARY, BINARY_INV, TRUNC, TOZERO, TOZERO_INV, OTSU, TRIANGLE, ADA_MEAN, ADA_GAUSS
};
class myDatatype {
public:
Mat &srcImg;
Mat &dstImg;
string winNames;
int methods;
myDatatype(Mat &srcImg_, Mat &dstImg_, string winNames_,int me_) : srcImg(srcImg_), dstImg(dstImg_),
winNames(winNames_),methods(me_){}
};
void onChange(int pos, void *Data) {
myDatatype data = *(myDatatype *) Data;
if(data.methods < 7){
threshold(data.srcImg, data.dstImg, pos, 255, data.methods);
}else{
adaptiveThreshold(data.srcImg,data.dstImg,255,data.methods,THRESH_BINARY_INV,5,5);
// 修改 thresholdType 的值 为 THRESH_BINARY_INV 或 THRESH_BINARY、blockSize大小、C的值
//adaptiveThreshold(data.srcImg,data.dstImg,255,data.methods,THRESH_BINARY,5,0);
}
imshow(data.winNames, data.dstImg);
}
int main(int argc, char **argv) {
Mat src = imread("/home/zzl/Blog/MonoMeasure/model/2.png", 1); // 输入图像
Mat src_gray;
cvtColor(src, src_gray, COLOR_BGR2GRAY);
string windowName = "Display";
namedWindow(windowName, WINDOW_NORMAL);
moveWindow(windowName, 1800, 200);
resizeWindow(windowName,Size(800,800));
imshow(windowName, src);
waitKey();
// 阈值处理
Mat dst_thres = Mat::zeros(src_gray.size(), CV_8UC1);
int methods = 0;
myDatatype Data(src_gray, dst_thres, windowName,methods);
int initValue = 30;
// 创建滑动条
createTrackbar("Threshold", windowName, &initValue, 255, onChange, &Data); // 使用自己创建的类传递数据,避免声明一大堆全局变量
createTrackbar("Methods", windowName, &methods, 8, onChange, &Data);
waitKey();
cout << "Hello World" << endl;
return 0;
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.17)
project(Threshold)
set(CMAKE_CXX_STANDARD 14)
find_package(OpenCV 4 REQUIRED)
message(STATUS "OpenCV library status:")
message(STATUS " OpenCV Version: ${OpenCV_VERSION}" )
include_directories(${OpenCV_INCLUDES})
add_executable(Threshold main.cpp )
target_link_libraries(Threshold${OpenCV_LIBS} )
参考博客:
https://blog.csdn.net/qq_45769063/article/details/107102117