opencv基础:基本阈值操作

184 阅读3分钟

1. 目标

在本文中,将学习如何:

2. 理论

  • 笔记

    下面的解释来自Bradski 和 Kaehler的《Learning OpenCV》一书。

3. 阈值

  • 最简单的分割方法

  • 应用示例:分离出感兴趣的图像区域。这种分离基于对象像素和背景像素之间的强度变化。

  • 为了感兴趣的像素与其余像素区分开来,将每个像素强度值与阈值(根据要解决的问题确定)进行比较。

  • 一旦正确地分离了重要的像素,就可以给它们设置一个确定的值来识别它们(即可以为它们分配一个值0(黑色的),255(白色)或任何满足需要的值)。

    Threshold_Tutorial_Theory_Example.jpg

3.1 阈值类型

  • OpenCV 提供函数cv::threshold来执行阈值操作。

  • 使用此函数可以完成5种阈值操作类型。将在以下小节中解释它们。

  • 为了说明这些阈值处理是如何工作的,假设有一个源图像,其中的像素具有强度值src(x,y). 下图描述了这一点。水平蓝线代表阈值。

    Threshold_Tutorial_Theory_Base_Figure.png

3.1.1 阈值二值化

  • 这个阈值操作可以表示为:

image.png

  • 所以,如果像素的强度src(x,y)高于阈值,则新的像素强度设置为maxVal. 否则,像素设置为0.

    Threshold_Tutorial_Theory_Binary.png

3.1.2 反向阈值二值化

  • 这个阈值操作可以表示为:

image.png

  • 如果像素的强度src(x,y)高于阈值,则新的像素强度设置为0. 否则设置为maxVal.

    Threshold_Tutorial_Theory_Binary_Inverted.png

3.1.3 截断

  • 这个阈值操作可以表示为:

image.png

  • 像素的最大强度值为阈值, 如果src(x,y)比阈值大,则其值被截断。见下图:

    Threshold_Tutorial_Theory_Truncate.png

3.1.4 阈值为零

  • 该操作可以表示为:

image.png

  • 如果src(x,y)低于阈值,新的像素值将被设置为0.

    Threshold_Tutorial_Theory_Zero.png

3.1.5 反向阈值为零

  • 该操作可以表示为:

image.png

  • 如果src(x,y)大于时间阈值,新的像素值将被设置为0.

    Threshold_Tutorial_Theory_Zero_Inverted.png

4. 代码

代码如下所示。可以从这里下载


#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
using namespace cv;
using std::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";
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 );
}
int main( int argc, char** argv )
{
    String imageName("stuff.jpg"); // by default
    if (argc > 1)
    {
        imageName = argv[1];
    }
    src = imread( samples::findFile( imageName ), IMREAD_COLOR ); // Load an image
    if (src.empty())
    {
        cout << "Cannot read the image: " << imageName << std::endl;
        return -1;
    }
    cvtColor( src, src_gray, COLOR_BGR2GRAY ); // Convert the image to Gray
    namedWindow( window_name, WINDOW_AUTOSIZE ); // Create a window to display results
    createTrackbar( trackbar_type,
                    window_name, &threshold_type,
                    max_type, Threshold_Demo ); // Create a Trackbar to choose type of Threshold
    createTrackbar( trackbar_value,
                    window_name, &threshold_value,
                    max_value, Threshold_Demo ); // Create a Trackbar to choose Threshold value
    Threshold_Demo( 0, 0 ); // Call the function to initialize
    waitKey();
    return 0;
}

5. 代码解释

下边查看以下程序的主干:

  • 加载图像。如果是 BGR,将其转换为灰度。使用函数cv::cvtColor

String imageName("stuff.jpg"); // by default
if (argc > 1)
{
        imageName = argv[1];
}
src = imread( samples::findFile( imageName ), IMREAD_COLOR ); // Load an image
if (src.empty())
{
        cout << "Cannot read the image: " << imageName << std::endl;
        return -1;
}
cvtColor( src, src_gray, COLOR_BGR2GRAY ); // Convert the image to Gray
  • 创建一个窗口来显示结果

 namedWindow( window_name, WINDOW_AUTOSIZE ); // Create a window to display results
  • 创造2个用户操作的轨迹栏:

    • 阈值类型:而致、归零等...
    • 阈值

createTrackbar( trackbar_type,
                    window_name, &threshold_type,
                    max_type, Threshold_Demo ); // Create a Trackbar to choose type of Threshold
    createTrackbar( trackbar_value,
                    window_name, &threshold_value,
                    max_value, Threshold_Demo ); // Create a Trackbar to choose Threshold value
  • 等到用户输入阈值,阈值的类型(或直到程序退出)
  • 每当用户更改任何 Trackbars 的值时,都会调用函数Threshold_Demo(Java 中的update ):
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 );
}

函数cv::threshold被调用,这个函数有5个参数:

  • src_gray : 输入图像
  • dst:目标(输出)图像
  • threshold_value:阈值
  • max_BINARY_value:与二值化阈值操作一起使用的值(用于设置所选像素)
  • threshold_type:5种阈值操作。它们列在上面函数的注释部分。

6. 结果

  1. 编译并运行,将图像的路径作为参数。例如,对于输入图像:

    Threshold_Tutorial_Original_Image.jpg

  2. 首先,尝试使用反向二值阈值。比阈值高的像素会变暗,在下面的快照中所见(从原始图像中可以看出,与图像相比,小狗的舌头和眼睛特别亮,所以会变暗,这反映在输出图像中)。

    Threshold_Tutorial_Result_Binary_Inverted.jpg

  3. 现在尝试将阈值设为零。有了这个,最暗的像素(低于阈值)将完全变黑,而值大于阈值的像素将保持其原始值。这通过以下输出图像的快照得到验证:

    Threshold_Tutorial_Result_Zero.jpg

原文地址