11.1 BasicLinearTransforms.cpp
调整输入图像的对比度和亮度,并显示原始图像和调整后的图像。程序中主要包含以下步骤:
-
读取用户输入的图像并做相应的错误处理。
-
创建一个新的图像矩阵用于存放调整对比度和亮度后的图像。
-
获取用户从命令行输入的对比度控制参数 alpha 和亮度控制参数 beta。
-
对原始图像中的每一个像素进行运算
new_image(i,j) = alpha*image(i,j) + beta
调整对比度和亮度。获取新的图像。 -
展示原始图像和新的图像。
-
程序挂起等待用户输入,一旦有输入,程序结束。
cpp
/**
* @file BasicLinearTransforms.cpp
* @brief 简单的程序用于调整图像的对比度和亮度
* @author OpenCV团队
*/
// 引入头文件
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp" //<-- 用于图像显示
#include <iostream> //<-- C++标准库中的输入/输出头文件
// 在此处,我们没有在全局范围内使用 "using namespace std;",是为了避免在 C++17 中 beta 变量与 std::beta产生冲突
using std::cin;
using std::cout;
using std::endl;
using namespace cv; // <-- 使用OpenCV中被封装在cv::下的所有的类和函数
/**
* @function main
* @brief 主函数
*/
int main( int argc, char** argv )
{
/// 读取用户输入的图像文件
//! [basic-linear-transform-load]
CommandLineParser parser( argc, argv, "{@input | lena.jpg | input image}" );
Mat image = imread( samples::findFile( parser.get<String>( "@input" ) ) );
if( image.empty() ) //<-- 判断图像是否读取成功
{
// 如果图像未被成功读取,则显示错误信息并返回-1,程序结束
cout << "Could not open or find the image!\n" << endl;
cout << "Usage: " << argv[0] << " <Input image>" << endl;
return -1;
}
//! [basic-linear-transform-load]
// 创建新的图像,准备存放调整对比度和亮度之后的图像
//! [basic-linear-transform-output]
Mat new_image = Mat::zeros( image.size(), image.type() );
//! [basic-linear-transform-output]
// 定义调整对比度和亮度的参数
//! [basic-linear-transform-parameters]
double alpha = 1.0; /*< 用于控制对比度的简单参数 */
int beta = 0; /*< 用于控制亮度的简单参数 */
/// 初始化值
cout << " Basic Linear Transforms " << endl;
cout << "-------------------------" << endl;
cout << "* Enter the alpha value [1.0-3.0]: "; cin >> alpha; //<-- 从控制台获取alpha值
cout << "* Enter the beta value [0-100]: "; cin >> beta; //<-- 从控制台获取beta值
//! [basic-linear-transform-parameters]
/// 执行操作 new_image(i,j) = alpha*image(i,j) + beta
/// 我们本可以简单的使用函数:image.convertTo(new_image, -1, alpha, beta); 来实现上述操作,
/// 但我们希望通过这个例子,展示出如何访问像素 :)
//! [basic-linear-transform-operation]
for( int y = 0; y < image.rows; y++ ) { //<-- 遍历图像的所有行
for( int x = 0; x < image.cols; x++ ) { //<-- 遍历图像的所有列
for( int c = 0; c < image.channels(); c++ ) { //<-- 遍历图像的每个通道
new_image.at<Vec3b>(y,x)[c] =
saturate_cast<uchar>( alpha*image.at<Vec3b>(y,x)[c] + beta ); //<-- 对原图像的每一个像素值执行操作调整对比度和亮度,saturate_cast<uchar>是为了确保计算结果落在uchar的取值范围
}
}
}
//! [basic-linear-transform-operation]
// 展示图像
//! [basic-linear-transform-display]
imshow("Original Image", image); // 显示原始图像
imshow("New Image", new_image); // 显示调整后的图像
// 等待用户按键,这样做是为了防止程序运行完后立即退出,无法显示图像
waitKey();
//! [basic-linear-transform-display]
return 0; //正常结束程序
}
11.2 Morphology_1.cpp
这段由OpenCV团队编写,对一张图片进行腐蚀和膨胀操作的C++代码。腐蚀操作会减小图像区域,膨胀操作会增大图像区域。主要通过设定腐蚀元素和膨胀元素的类型以及内核大小,然后调用库函数进行腐蚀或者膨胀操作,来改变图像的性质。可以视为一种提取图像特征的方法,常应用于图像二值化、边缘检测、消除噪声等图像处理操作中。
cpp
/**
* @file Morphology_1.cpp
* @brief Erosion and Dilation sample code 腐蚀与膨胀的样例代码
* @author OpenCV team
*/
#include "opencv2/imgproc.hpp" //包含OpenCV库头文件
#include "opencv2/highgui.hpp" //包含OpenCV高级用户界面的头文件
#include <iostream>
using namespace cv;
using namespace std;
/// Global variables 定义全局变量
Mat src, erosion_dst, dilation_dst;
int erosion_elem = 0;
int erosion_size = 0;
int dilation_elem = 0;
int dilation_size = 0;
int const max_elem = 2;
int const max_kernel_size = 21;
/** Function Headers 函数的声明(函数的原型) */
void Erosion( int, void* ); // 腐蚀函数
void Dilation( int, void* ); // 膨胀函数
/**
* @function main 主函数
*/
int main( int argc, char** argv )
{
/// Load an image, 加载图片
CommandLineParser parser( argc, argv, "{@input | LinuxLogo.jpg | input image}" );
src = imread( samples::findFile( parser.get<String>( "@input" ) ), IMREAD_COLOR );
if( src.empty() )
{
cout << "Could not open or find the image!\n" << endl; //若图片为空,打印错误信息
cout << "Usage: " << argv[0] << " <Input image>" << endl;
return -1;
}
/// Create windows 创建窗口
namedWindow( "Erosion Demo", WINDOW_AUTOSIZE );
namedWindow( "Dilation Demo", WINDOW_AUTOSIZE );
moveWindow( "Dilation Demo", src.cols, 0 );
/// Create Erosion Trackbar 创建腐蚀的滑动条
createTrackbar( "Element:\n 0: Rect \n 1: Cross \n 2: Ellipse", "Erosion Demo",
&erosion_elem, max_elem,
Erosion );
createTrackbar( "Kernel size:\n 2n +1", "Erosion Demo",
&erosion_size, max_kernel_size,
Erosion );
/// Create Dilation Trackbar 创建膨胀的滑动条
createTrackbar( "Element:\n 0: Rect \n 1: Cross \n 2: Ellipse", "Dilation Demo",
&dilation_elem, max_elem,
Dilation );
createTrackbar( "Kernel size:\n 2n +1", "Dilation Demo",
&dilation_size, max_kernel_size,
Dilation );
/// Default start 默认开始
Erosion( 0, 0 );
Dilation( 0, 0 );
waitKey(0); //等待用户按键操作
return 0;
}
/**
* @function Erosion 腐蚀函数
*/
void Erosion( int, void* )
{
int erosion_type = 0;
if( erosion_elem == 0 ){ erosion_type = MORPH_RECT; } //如果元素类型为0,腐蚀的类型为MORPH_RECT
else if( erosion_elem == 1 ){ erosion_type = MORPH_CROSS; } //如果元素类型为1,腐蚀的类型为MORPH_CROSS
else if( erosion_elem == 2) { erosion_type = MORPH_ELLIPSE; } //如果元素类型为2,腐蚀的类型为MORPH_ELLIPSE
//![kernel]
Mat element = getStructuringElement( erosion_type, //生成预定义形状的结构元素
Size( 2*erosion_size + 1, 2*erosion_size+1 ),
Point( erosion_size, erosion_size ) );
//![kernel]
/// Apply the erosion operation 进行腐蚀操作
erode( src, erosion_dst, element );
imshow( "Erosion Demo", erosion_dst ); //显示腐蚀的效果
}
/**
* @function Dilation 膨胀函数
*/
void Dilation( int, void* )
{
int dilation_type = 0;
if( dilation_elem == 0 ){ dilation_type = MORPH_RECT; } //如果元素类型为0,膨胀的类型为MORPH_RECT
else if( dilation_elem == 1 ){ dilation_type = MORPH_CROSS; } //如果元素类型为1,膨胀的类型为MORPH_CROSS
else if( dilation_elem == 2) { dilation_type = MORPH_ELLIPSE; } //如果元素类型为2,膨胀的类型为MORPH_ELLIPSE
Mat element = getStructuringElement( dilation_type, //生成预定义形状的结构元素
Size( 2*dilation_size + 1, 2*dilation_size+1 ),
Point( dilation_size, dilation_size ) );
/// Apply the dilation operation 进行膨胀操作
dilate( src, dilation_dst, element );
imshow( "Dilation Demo", dilation_dst ); //显示膨胀的效果
}
11.3 Morphology_2.cpp
这段代码的主要功能是实现形态学操作,如:开运算、闭运算、形态学梯度、顶帽运算和黑帽运算,用户可以自行选择操作类型及形状和大小的结构元素,以观察不同设置下的形态学操作效果
cpp
/**
* @file Morphology_2.cpp
* @brief 封装了一些形态学变换的高级示例代码
* @author OpenCV团队
*/
#include "opencv2/imgproc.hpp" //包含了图像处理方面的函数和类
#include "opencv2/imgcodecs.hpp" //包含了图像编码/解码方面的函数和类
#include "opencv2/highgui.hpp" //包含了图像显示方面的函数和类
#include <iostream> //标准输入输出库
using namespace cv; //使用OpenCV的命名空间
/// 全局变量
Mat src, dst; //定义两个Mat类型的变量,src和dst,分别用来存储原图和处理后的图像
int morph_elem = 0; //定义一个变量,用于切换形态学处理的内核类型
int morph_size = 0; //定义一个变量,用于改变形态学处理的内核大小
int morph_operator = 0; //定义一个变量,用于切换不同的形态学操作
int const max_operator = 4; //定义操作类型的最大值
int const max_elem = 2; //定义内核类型的最大值
int const max_kernel_size = 21; //定义内核大小的最大值
const char* window_name = "Morphology Transformations Demo"; //定义程序窗口的标题
/** 函数声明 */
void Morphology_Operations( int, void* );
/**
* @function main
*/
int main( int argc, char** argv )
{
//![load]
CommandLineParser parser( argc, argv, "{@input | baboon.jpg | 输入图片}" );
//使用parser获取的参数,从文件加载图像到src,加载方式为色彩图像
src = imread( samples::findFile( parser.get<String>( "@input" ) ), IMREAD_COLOR );
//如果原图为空,则输出错误信息并返回
if (src.empty())
{
std::cout << "无法打开或找到图像!\n" << std::endl;
std::cout << "使用方法: " << argv[0] << " <输入图像>" << std::endl;
return EXIT_FAILURE;
}
//![load]
//![window]
namedWindow( window_name, WINDOW_AUTOSIZE ); //创建一个名为window_name的窗口,窗口大小自适应图像大小
//![window]
//![create_trackbar1]
/// 创建滚动条来选择形态学操作类型
createTrackbar("Operator:\n 0: 开运算 - 1: 闭运算 \n 2: 形态学梯度 - 3: 顶帽运算 \n 4: 黑帽运算", window_name, &morph_operator, max_operator, Morphology_Operations );
//![create_trackbar1]
//![create_trackbar2]
/// 创建滚动条来选择内核类型
createTrackbar( "Element:\n 0: 矩形 - 1: 十字形 - 2: 椭圆形", window_name,
&morph_elem, max_elem,
Morphology_Operations );
//![create_trackbar2]
//![create_trackbar3]
/// 创建滚动条来选择内核大小
createTrackbar( "Kernel size:\n 2n +1", window_name,
&morph_size, max_kernel_size,
Morphology_Operations );
//![create_trackbar3]
/// 默认开始
Morphology_Operations( 0, 0 ); //调用形态学操作处理函数
waitKey(0); //等待用户按键
return 0; //程序正常退出
}
//![morphology_operations]
/**
* @function Morphology_Operations
*/
void Morphology_Operations( int, void* )
{
// 在MORPH_X中:2,3,4,5和6
//![operation]
int operation = morph_operator + 2; //根据用户选择,确定形态学操作的类型
//![operation]
//构建指定类型和大小的内核元素
Mat element = getStructuringElement( morph_elem, Size( 2*morph_size + 1, 2*morph_size+1 ), Point( morph_size, morph_size ) );
/// 应用指定的形态学操作
morphologyEx( src, dst, operation, element ); //执行形态学操作
imshow( window_name, dst ); //在窗口中显示处理后的图像
}
//![morphology_operations]
11.4 Threshold.cpp
代码主要实现了在给定图像上应用不同类型的阈值处理,并通过创建的滑动条手动选择阈值类型以及阈值大小,进而观察不同阈值类型和大小对图像处理效果的影响。阈值处理通常应用于图像分割、特征提取等操作,是计算机视觉领域的基本技术之一。
cpp
/**
* @file Threshold.cpp
* @brief 这是一个示例代码,演示如何使用OpenCV提供的各种阈值策略
* @author OpenCV团队
*/
#include "opencv2/imgproc.hpp" // 引用OpenCV库处理图像处理部分
#include "opencv2/imgcodecs.hpp" // 用于处理图像编码和解码带
#include "opencv2/highgui.hpp" // 提供创建窗口,加载图像等与高级图形用户界面相关的功能
#include <iostream> // 引用标准输入输出库
using namespace cv; // 使用命名空间cv,方便代码中直接用OpenCV函数
using std::cout; // 使用标准命名空间中的cout
/// 全局变量
int threshold_value = 0; // 阈值
int threshold_type = 3; // 阈值类型
int const max_value = 255; // 最大值常数
int const max_type = 4; // 最大类型常数
int const max_binary_value = 255; // 二值图像最大像素值
Mat src, src_gray, dst; // 声明原图、灰度图和目标图像矩阵
const char* window_name = "Threshold Demo"; // 窗口名称
const char* trackbar_type = "Type: \n 0: Binary \n 1: Binary Inverted \n 2: Truncate \n 3: To Zero \n 4: To Zero Inverted";
const char* trackbar_value = "Value"; // 滑动条上显示的提示文字
//![阈值处理函数]
/**
* @function Threshold_Demo
*/
static void Threshold_Demo( int, void* )
{
/* 0: Binary 二值阈值
1: Binary Inverted 反转二值阈值
2: Threshold Truncated 截断阈值
3: Threshold to Zero 零设置阈值
4: Threshold to Zero Inverted 反转零设置阈值
*/
threshold( src_gray, dst, threshold_value, max_binary_value, threshold_type ); // 应用阈值进行图像分割
imshow( window_name, dst ); // 显示处理后的图像
}
//![阈值处理函数]
/**
* @function main
*/
int main( int argc, char** argv )
{
//! [load]
String imageName("stuff.jpg"); // 默认图像文件名
if (argc > 1)
{
imageName = argv[1]; // 如果有输入参数,第一个参数作为图像文件名
}
src = imread( samples::findFile( imageName ), IMREAD_COLOR ); // 读取图像文件
if (src.empty())
{
cout << "Cannot read the image: " << imageName << std::endl; // 如果图像读取失败,打印错误信息
return -1;
}
cvtColor( src, src_gray, COLOR_BGR2GRAY ); // 将图像转化为灰度图
//! [load]
//! [window]
namedWindow( window_name, WINDOW_AUTOSIZE ); // 创建窗口用以显示结果
//! [window]
//! [trackbar]
createTrackbar( trackbar_type,
window_name, &threshold_type,
max_type, Threshold_Demo ); // 创建滑动条以选择阈值类型
createTrackbar( trackbar_value,
window_name, &threshold_value,
max_value, Threshold_Demo ); // 创建滑动条以选择阈值大小
//! [trackbar]
Threshold_Demo( 0, 0 ); // 初始化并调用阈值处理函数
/// 等待用户操作结束程序
waitKey();
return 0;
}
如何确定使用哪种阈值处理方式来处理图像?
阈值处理是图像处理中的哪一步骤?
阈值处理可以在哪些应用场景中使用?
阈值处理如何在目标检测中应用?
11.5 Threshold_inRange.cpp
这段代码的功能是通过设定HSV色彩空间的阈值来检测颜色,并利用滑动条可实时调整阈值,用以监测摄像头(或者视频)中特定颜色的物体,用于实时颜色追踪的应用。
cpp
#include "opencv2/imgproc.hpp" // 引入opencv图像处理库
#include "opencv2/highgui.hpp" // 引入opencv高级GUI库
#include "opencv2/videoio.hpp" // 引入opencv的视频输入输出库
#include <iostream> // 引入标准输入输出库
using namespace cv; // 使用命名空间cv,opencv核心库中的所有函数和方法都被定义在cv的命名空间下(包含图像处理、数据结构等主要模块)
/** 全局变量 */
const int max_value_H = 360/2; // 定义 HSV 色调的最大值
const int max_value = 255; // 定义 HSV 饱和度和亮度的最大值
const String window_capture_name = "Video Capture"; // 定义视频捕获窗口的名称
const String window_detection_name = "Object Detection"; // 定义物体检测窗口的名称
int low_H = 0, low_S = 0, low_V = 0; // 定义 HSV 颜色空间分别对应色调、饱和度和亮度的最低阈值
int high_H = max_value_H, high_S = max_value, high_V = max_value; // 定义 HSV 颜色空间分别对应色调、饱和度和亮度的最高阈值
//! [low]
static void on_low_H_thresh_trackbar(int, void *) // 当滑动条的值改变时,调用此回调函数,更新低阈值
{
low_H = min(high_H-1, low_H); // 确保低阈值总是小于高阈值
setTrackbarPos("Low H", window_detection_name, low_H); // 设置滑动条的位置
}
//! [low]
//! [high]
static void on_high_H_thresh_trackbar(int, void *) // 当滑动条的值改变时,调用此回调函数,更新高阈值
{
high_H = max(high_H, low_H+1); // 确保高阈值总是大于低阈值
setTrackbarPos("High H", window_detection_name, high_H); // 设置滑动条的位置
}
static void on_low_S_thresh_trackbar(int, void *) // 更新饱和度的低阈值
{
low_S = min(high_S-1, low_S);
setTrackbarPos("Low S", window_detection_name, low_S);
}
static void on_high_S_thresh_trackbar(int, void *) // 更新饱和度的高阈值
{
high_S = max(high_S, low_S+1);
setTrackbarPos("High S", window_detection_name, high_S);
}
static void on_low_V_thresh_trackbar(int, void *) // 更新亮度的低阈值
{
low_V = min(high_V-1, low_V);
setTrackbarPos("Low V", window_detection_name, low_V);
}
static void on_high_V_thresh_trackbar(int, void *) // 更新亮度的高阈值
{
high_V = max(high_V, low_V+1);
setTrackbarPos("High V", window_detection_name, high_V);
}
int main(int argc, char* argv[]) // 主函数
{
//! [cap]
VideoCapture cap(argc > 1 ? atoi(argv[1]) : 0); // 创建视频捕获对象,如果程序有参数,使用参数作为视频源,否则使用默认摄像头
//! [cap]
//! [window]
namedWindow(window_capture_name); // 创建视频捕获窗口
namedWindow(window_detection_name); // 创建物体检测窗口
//! [window]
//! [trackbar]
// 创建滑动条,并设置HSV值的阈值
createTrackbar("Low H", window_detection_name, &low_H, max_value_H, on_low_H_thresh_trackbar);
createTrackbar("High H", window_detection_name, &high_H, max_value_H, on_high_H_thresh_trackbar);
createTrackbar("Low S", window_detection_name, &low_S, max_value, on_low_S_thresh_trackbar);
createTrackbar("High S", window_detection_name, &high_S, max_value, on_high_S_thresh_trackbar);
createTrackbar("Low V", window_detection_name, &low_V, max_value, on_low_V_thresh_trackbar);
createTrackbar("High V", window_detection_name, &high_V, max_value, on_high_V_thresh_trackbar);
//! [trackbar]
Mat frame, frame_HSV, frame_threshold; // 定义三个Mat对象,用于存储原始帧,HSV色彩空间帧和阈值帧
while (true) { // 循环处理每一帧
//! [while]
cap >> frame; // 读取一帧
if(frame.empty()) // 如果帧为空说明视频已经结束
{
break;
}
cvtColor(frame, frame_HSV, COLOR_BGR2HSV); // 将原始帧从BGR色彩空间转换到HSV色彩空间
inRange(frame_HSV, Scalar(low_H, low_S, low_V), Scalar(high_H, high_S, high_V), frame_threshold); // 通过HSV阈值,对帧进行二值化处理
//! [while]
//! [show]
imshow(window_capture_name, frame); // 显示原始帧
imshow(window_detection_name, frame_threshold); // 显示二值化处理后的帧
//! [show]
char key = (char) waitKey(30); // 等待键盘输入,如果按下'q'或者ESC键,跳出循环
if (key == 'q' || key == 27)
{
break;
}
}
return 0;
}
Threshold_Tutorial_Theory_Base_Figure
Threshold_Tutorial_Theory_Binary.png
Threshold_Tutorial_Theory_Binary_Inverted.png
Threshold_Tutorial_Theory_Truncate.png
Threshold_Tutorial_Theory_Zero.png
Threshold_Tutorial_Theory_Zero_Inverted.png