Opencv-C++笔记 (11) : opencv-图像二值化与LUB查找表

news2024/11/28 2:40:59

文章目录

  • 一、概述
  • 二、THRESH_BINARY和THRESH_BINARY_INV
  • 三、THRESH_TRUNC
  • 四、THRESH_TOZERO和THRESH_TOZERO_INV
  • 五、THRESH_OTSU和THRESH_TRIANGLE
  • 六、LUT查找表

一、概述

我们在上一节程序中生成了一张只有黑色和白色的图像,这种“非黑即白”的图像像素的灰度值无论在什么数据类型中只有最大值和最小值两种取值,因此称其为二值图像。二值图像色彩种类少,可以进行高度的压缩,节省存储空间,将非二值图像经过计算变成二值图像的过程称为图像的二值化。在OpenCV4中提供了threshold()和adaptiveThreshold()两个函数用于实现图像的二值化,我们首先介绍threshold()函数的使用方法,该函数的函数原型在代码清单3-17中给出。

double cv::threshold(InputArray src,OutputArray dst,double  thresh,double  maxval,int  type)
  • src:待二值化的图像,图像只能是CV_8U和CV_32F两种数据类型。对于图像通道数目的要求和选择的二值化方法相关。
  • dst:二值化后的图像,与输入图像具有相同的尺寸、数据类型和通道数。
  • thresh:二值化的阈值。
  • maxval:二值化过程的最大值,此函数只在THRESH_BINARY和THRESH_BINARY_INV两种二值化方法中才使用,但是在使用其他方法是也需要输入。
  • type:选择图像二值化方法的标志。

该函数是众多二值化方法的集成,所有的方法都实现了一个功能,就是给定一个阈值,计算所有像素灰度值与这个阈值关系,得到最终的比较结果。函数中有些阈值比较方法输出结果的灰度值并不是二值的,而是具有一个取值范围,不过为了体现其最常用的功能,我们仍然称其为二值化函数或者阈值比较函数。函数的部分参数和返回值都是针对特定的算法才有用,但是即使不使用这些算法在使用函数时也需要明确的给出,不可缺省。函数的最后一个参数是选择二值化计算方法的标志,可以选择二值化方法以及控制哪些参数对函数的计算结果产生影响,该标志可以选择的范围及含义在表3-2中给出。
在这里插入图片描述

接下来将详细的介绍每种标志对应的二值化原理和需要的参数。

二、THRESH_BINARY和THRESH_BINARY_INV

这两个标志是相反的二值化方法,THRESH_BINARY是将灰度值与阈值(第三个参数thresh)进行比较,如果灰度值大于阈值就将灰度值改为函数中第四个参数maxval的值,否则将灰度值改成0。THRESH_BINARY_INV标志正好与这个过程相反,如果灰度值大于阈值就将灰度值改为0,否则将灰度值改为maxval的值。这两种标志的计算公式在式(3.7)中给出。
在这里插入图片描述

三、THRESH_TRUNC

这个标志相当于重新给图像的灰度值设定一个新的最大值,将大于新的最大值的灰度值全部重新设置为新的最大值,具体逻辑为将灰度值与阈值thresh进行比较,如果灰度值大于thresh则将灰度值改为thresh,否则保持灰度值不变。这种方法没有使用到函数中的第四个参数maxval的值,因此maxval的值对本方法不产生影响。这种标志的计算公式在式(3.8)中给出。

在这里插入图片描述

四、THRESH_TOZERO和THRESH_TOZERO_INV

这两个标志是相反的阈值比较方法, THRESH_TOZERO表示将灰度值与阈值thresh进行比较,如果灰度值大于thresh则将保持不变,否则将灰度值改为0。THRESH_TOZERO_INV方法与其相反,将灰度值与阈值thresh进行比较,如果灰度值小于等于thresh则将保持不变,否则将灰度值改为0。这种两种方法都没有使用到函数中的第四个参数maxval的值,因此maxval的值对本方法不产生影响。这两个标志的计算公式在式(3.9)中给出。
在这里插入图片描述
前面五种标志都支持输入多通道的图像,在计算时分别对每个通道进行阈值比较。为了更加直观的理解上述阈值比较方法,我们假设图像灰度值是连续变化的信号,将阈值比较方法比做滤波器,绘制连续信号通过滤波器后的信号形状,结果如图3-14所示,图中红线为设置的阈值,黑线为原始信号通过滤波器后的信号形状。
在这里插入图片描述

五、THRESH_OTSU和THRESH_TRIANGLE

这两种标志是获取阈值的方法,并不是阈值的比较方法的标志,这两个标志可以和前面5种标志一起使用,例如“THRESH_BINARY|THRESH_OTSU”。前面5种标志在调用函数时都需要人为的设置阈值,如果对图像不了解设置的阈值不合理,会对处理后的效果造成严重的影响,这两个标志分别表示利用**大津法(OTSU)和三角形法(TRIANGLE)**结合图像灰度值分布特性获取二值化的阈值,并将阈值以函数返回值的形式给出。因此如果函数最后一个参数设置了这两个标志中的任何一个,那么函数第三个参数thresh将由系统自动给出,但是在调用函数的时候仍然不能缺省,只是程序不会使用这个数值。需要注意的是,目前为止OpenCV
4中针对这两个标志只支持输入CV_8UC1类型的图像。

threshold()函数全局只使用一个阈值,在实际情况中由于光照不均匀以及阴影的存在,全局只有一个阈值会使得在阴影处的白色区域也会被函数二值化成黑色,因此adaptiveThreshold()函数提供了两种局部自适应阈值的二值化方法,该函数的函数原型在代码清单3-18中给出。

void cv::adaptiveThreshold(InputArray src,
                                 OutputArray dst,
                                double  maxValue,
                                int  adaptiveMethod,
                                 int  thresholdType,
                                 int  blockSize,
                                double   C
                                  )
  • src:待二值化的图像,图像只能是CV_8UC1数据类型。
  • dst:二值化后的图像,与输入图像具有相同的尺寸、数据类型。
  • maxValue:二值化的最大值。
  • adaptiveMethod:自制应确定阈值的方法,分为均值法ADAPTIVE_THRESH_MEAN_C和高斯法ADAPTIVE_THRESH_GAUSSIAN_C这两种。
  • thresholdType:选择图像二值化方法的标志,只能是THRESH_BINARY和THRESH_BINARY_INV。
  • blockSize:自适应确定阈值的像素邻域大小,一般为3,5,7的奇数。 C:从平均值或者加权平均值中减去的常数,可以为正,也可以为负。

该函数将灰度图像转换成二值图像,通过均值法和高斯法自适应的计算blockSize* blockSize邻域内的阈值,之后进行二值化,其原理与前面的相同,这里就不再赘述。

为了直观的体会到图像二值化的效果,在代码清单3-19中给出了分别对彩色图像和灰度图像进行二值化的示例程序

#include<iostream>
#include<vector>
#include<string>
#include <opencv2/opencv.hpp>
#include "opencv/highgui.h"

using namespace std;
using namespace cv;

int main(int argc,char** argv) {
    cout<<"OpenCv Version: "<<CV_VERSION<<endl;
    Mat img=imread("699342568.jpg");
    if(img.empty()){
        cout<<"请确认输入的图片的路径是否正确"<<endl;
        return -1;
    }

    Mat gray;
    cvtColor(img,gray,COLOR_BGR2GRAY);
    Mat img_B,img_B_V,gray_B,gray_B_V,gray_T,gray_T_V,gray_TRUNC;

    //彩色图像二值化
    threshold(img,img_B,125,255,THRESH_BINARY);
    threshold(img,img_B_V,125,255,THRESH_BINARY_INV);
    imshow("img_B",img_B);
    imshow("img_B_V",img_B_V);

    //灰度图像二值化
    threshold(gray,gray_B,125,255,THRESH_BINARY);
    threshold(gray,gray_B_V,125,255,THRESH_BINARY_INV);
    imshow("gray_B",gray_B);
    imshow("gray_B_V",gray_B_V);

    //灰度图像TOZERO变换
    threshold(gray,gray_T,125,255,THRESH_TOZERO);
    threshold(gray,gray_T_V,125,255,THRESH_TOZERO_INV);
    imshow("gray_T",gray_T);
    imshow("gray_T_V",gray_T_V);

    //灰度图像TRUNC变换
    threshold(gray,gray_TRUNC,125,255,THRESH_TRUNC);
    imshow("gray_TRUNC",gray_TRUNC);

    //灰度图像大津法和三角法二值化
    Mat img_Thr=imread("threshold.jpg",IMREAD_GRAYSCALE);
    Mat img_Thr_0,img_Thr_T;
    threshold(img_Thr,img_Thr_0,100,255,THRESH_BINARY|THRESH_OTSU);
    threshold(img_Thr,img_Thr_T,125,255,THRESH_BINARY|THRESH_TRIANGLE);
    imshow("img_Thr",img_Thr);
    imshow("img_Thr_0",img_Thr_0);
    imshow("img_Thr_T",img_Thr_T);

    //灰度图像自适应二值化
    Mat adaptive_mean,adaptive_gauss;
    adaptiveThreshold(img_Thr,adaptive_mean,255,ADAPTIVE_THRESH_MEAN_C,THRESH_BINARY,55,0);
    adaptiveThreshold(img_Thr,adaptive_gauss,255,ADAPTIVE_THRESH_GAUSSIAN_C,THRESH_BINARY,55,0);

    imshow("adaptive_mean",adaptive_mean);
    imshow("adaptive_gauss",adaptive_gauss);
    waitKey(0);
    return 0;
}

在这里插入图片描述

六、LUT查找表

阈值比较方法中只有一个阈值,如果需要与多个阈值进行比较,就需要用到显示查找表(Look-Up-Table,LUT)。LUT查找表简单来说就是一个像素灰度值的映射表,它以像素灰度值作为索引,以灰度值映射后的数值作为表中的内容。例如我们有一个长度为5的存放字符的数组,LUT查找表就是通过这个数组将0映射成a,将1映射成b,依次类推,其映射关系为。在OpenCV
4中提供了LUT()函数用于实现图像像素灰度值的LUT查找表功能,在代码清单3-20中给出了该函数的原型。

 void cv::LUT(InputArray src,
                   InputArray lut,
                   OutputArray dst
                  )
  • src:输入图像矩阵,其数据类型只能是CV_8U。

  • lut:256个像素灰度值的查找表,单通道或者与src通道数相同。

-dst:输出图像矩阵,其尺寸与src相同,数据类型与lut相同。

该函数的第一个输入参数要求的数据类型必须是CV_8U类型,但是可以是多通道的图像矩阵。第二个参数根据其参数说明可以知道输入量是一个1×256的矩阵,其中存放着每个像素灰度值映射后的数值,其形式如图3-17所示。如果第二个参数是单通道,则输入变量中的每个通道都按照一个LUT查找表进行映射;如果第二个参数是多通道,则输入变量中的第i个通道按照第二个参数的第i个通道LUT查找表进行映射。与之前的函数不同,函数输出图像的数据类型不与原图像的数据类型保持一致,而是和LUT查找表的数据类型保持一致,这是因为将原灰度值映射到新的空间中,因此需要与新空间中的数据类型保持一致。
在这里插入图片描述

为了体会LUT查找表处理图像后的效果,在代码清单3-21中给出通过LUT()函数将灰度图像和彩色图像分别处理的示例程序,程序中分别应用单通道和三通道的查找表对彩色图像进行映射

#include<iostream>
#include<vector>
#include<string>
#include <opencv2/opencv.hpp>
#include "opencv/highgui.h"

using namespace std;
using namespace cv;

int main(int argc,char** argv) {
    cout<<"OpenCv Version: "<<CV_VERSION<<endl;
    //LUT查找表第一层
    uchar lutFirst[256];
    for(int i=0;i<256;++i){
        if(i<=100)lutFirst[i]=0;
        else if(i>100&&i<=200)lutFirst[i]=100;
        else lutFirst[i]=255;
    }
    Mat lutOne(1,256,CV_8UC1,lutFirst);

    //LUT查找表第二层
    uchar lutSecond[256];
    for(int i=0;i<256;++i){
        if(i<=100)lutSecond[i]=0;
        else if(i>100&&i<=150)lutSecond[i]=100;
        else if(i>150&&i<=200)lutSecond[i]=150;
        else lutSecond[i]=255;
    }
    Mat lutTwo(1,256,CV_8UC1,lutSecond);

    //LUT查找表第三层
    uchar lutThird[256];
    for(int i=0;i<256;++i){
        if(i<=100)lutThird[i]=0;
        else if(i>100&&i<=200)lutThird[i]=100;
        else lutThird[i]=255;
    }
    Mat lutThree(1,256,CV_8UC1,lutThird);

    //拥有三通道的LUT查找表矩阵
    vector<Mat>mergeMats;
    mergeMats.push_back(lutOne);
    mergeMats.push_back(lutTwo);
    mergeMats.push_back(lutThree);
    Mat LutTree;
    merge(mergeMats,LutTree);

    //计算图像的查找表
    Mat img=imread("lena.jpeg");
    if(img.empty()){
        cout<<"请确认输入的图片路径是否正确"<<endl;
        return -1;
    }
    Mat gray,out0,out1,out2;
    cvtColor(img,gray,COLOR_BGR2GRAY);
    LUT(gray,lutOne,out0);
    LUT(img,lutOne,out1);
    LUT(img,LutTree,out2);
    imshow("out0",out0);
    imshow("out1",out1);
    imshow("out2",out2);
    waitKey(0);
    return 0;
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/664775.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MFC 非线程创建模态化窗口 实现工具栏拓展

1 实现基本工具栏 1.1 在Dlg.h文件中声明变量和定义资源ID #define ID_BUTTONS 501CToolBar m_toolbar; //工具栏 CImageList m_imageList; //工具栏图片 CImageList m_hotImageList; //工具栏热点图片 CReBar m_Rebar; //可以在位图上显示子窗口口 用来显示背景 CString…

【DeepLearning】Ubuntu中深度学习环境配置完整流程

Ubuntu中深度学习环境配置完整流程 1 显卡驱动2 cuda3 cuDNN4 torch5 torchvision 1 显卡驱动 支持 cuda 的所有显卡型号: Link 查询显卡型号 lspci -nn | grep VGA即 Vendor ID:Device ID 为 10de:21c4&#xff0c;在浏览器或者 Link 中搜索。 填写显卡信息: Link 选择要下载…

Jenkins-pipeline自动化构建Java应用

本实验操作需要&#xff1a;Jenkins&#xff0c;git代码仓库&#xff08;如gitlab&#xff0c;gitee等都可以&#xff09;&#xff0c;maven&#xff0c;docker&#xff0c;docker镜像仓库&#xff08;habor&#xff0c;nexus或者阿里云ACR等&#xff09;以及k8s环境。 前期准…

nginx特点以及安装

目录 1.特点 2.nginx和apache的区别 3.nginx应用场景 4.安装nginx 5. 更新nginx版本 6.总结 1.特点 高性能 轻量级web服务软件 稳定性高 系统自选消耗低 对http并发链接处理能力高 #处理并发连接能力 1.cup个数 2.本地服务器最大文件打开数 2.nginx和apache的区别 ng…

chatgpt赋能python:打包Python应用程序成deb包

打包Python应用程序成deb包 随着Python编程语言的不断发展&#xff0c;越来越多的开发者使用Python编写应用程序。然而&#xff0c;将Python程序打包并制作成deb包以进行安装可能仍然是一个难点。本文将介绍如何使用Debian打包工具&#xff0c;将Python应用程序制作成deb包。 …

chatgpt赋能python:Python扩展库介绍

Python扩展库介绍 Python是一种广泛使用的编程语言&#xff0c;它的易用性和可扩展性是许多开发者选择它的原因之一。这个语言有着丰富的扩展库&#xff0c;让开发者能够更加高效地编写代码。在这篇SEO文章中&#xff0c;我们将介绍几个与Python相关的扩展库。 NumPy NumPy是…

RPC远程调用

简介 PRC是一种调用方式而不是一种协议 在本地调用方式时由于方法在同一个内存空间&#xff0c;所以程序中可以直接调用该方法&#xff0c;但是浏览器端和服务端程序是不在一个内存空间的&#xff0c;需要使用网络来访问&#xff0c;就需要使用TCP或者UDP协议&#xff0c;由于…

使用frp工具实现内网穿透以及配置多个ssh和web服务

frp简介 FRP 项目地址 https://github.com/fatedier/frp/blob/master/README_zh.md frp 是一个可用于内网穿透的高性能的反向代理应用,支持 tcp, udp 协议,为 http 和 https 应用协议提供了额外的能力,且尝试性支持了点对点穿透。 环境准备 ssh连接 1. 需要一台可以直接访问…

简要介绍 | 交叉熵损失:原理和研究现状

注1&#xff1a;本文系“简要介绍”系列之一&#xff0c;仅从概念上对交叉熵损失进行非常简要的介绍&#xff0c;不适合用于深入和详细的了解。 注2&#xff1a;"简要介绍"系列的所有创作均使用了AIGC工具辅助 交叉熵损失&#xff1a;原理、研究现状与未来展望 Under…

Web3 是什么?为何应该关注?

当我开始我的职业生涯时&#xff0c;“Web2.0”还是一个热门的新事物。 当我开始我的职业生涯时&#xff0c;正值互联网快速发展的时期&#xff0c;人们谈论的是“Web2.0”&#xff0c;这一概念引发了许多关于用户参与、社交媒体和在线合作的讨论。然而&#xff0c;随着时间的推…

SQL优化--如何分析优化呢?

目录 一个SQL语句执行很慢, 如何分析&#xff1f; ​编辑 重要属性 possible_key key key_len Extra type 面试回答 框架 范例 例&#xff1a; 上面三种查询我们都可以通过执行计划找到查询慢的原因&#xff0c;并且提供解决方案 比如聚合查询可以新增临时表&…

【Leetcode -563.二叉树的坡度 - Nowcoder -KY11.二叉树遍历】

Leetcode Leetcode -563.二叉树的坡度c Leetcode -563.二叉树的坡度 题目&#xff1a;给你一个二叉树的根节点 root &#xff0c;计算并返回 整个树 的坡度 。 一个树的 节点的坡度 定义即为&#xff0c;该节点左子树的节点之和和右子树节点之和的 差的绝对值 。如果没有左子树…

leetcode数据库题第五弹

leetcode数据库题第五弹 1141. 查询近30天活跃用户数1148. 文章浏览 I1158. 市场分析 I1164. 指定日期的产品价格1174. 即时食物配送 II1179. 重新格式化部门表1193. 每月交易 I1204. 最后一个能进入电梯的人1211. 查询结果的质量和占比1251. 平均售价小结 1141. 查询近30天活跃…

chatgpt赋能python:Python打开文件目录:入门指南

Python打开文件目录&#xff1a;入门指南 打开文件目录是编程中常见的操作之一。Python 作为一种优秀的脚本语言&#xff0c;提供了众多的实用方法来操作文件系统。在本文中&#xff0c;我们将介绍如何使用 Python 打开文件目录&#xff0c;同时提供一些对 SEO 优化有帮助的技…

NodeJS 生成APIDOC⑩①

文章目录 ✨文章有误请指正&#xff0c;如果觉得对你有用&#xff0c;请点三连一波&#xff0c;蟹蟹支持&#x1f618;前言API 文档生成工具 APIDOC特点 APIDOC使用步骤0、 运行命令1、 安装插件3、 配置演示4、 ApidocJson配置文件5、效果图 总结 ✨文章有误请指正&#x…

Storm forming 风雨欲来 | 经济学人20230325版社论高质量双语精翻

本期精翻为2023年3月25日《经济学人》周报封面文章&#xff1a;《风雨欲来》&#xff08;Storm forming&#xff09;。 Storm forming 风雨欲来 As video games grow, they are eating the media 随着电子游戏的发展&#xff0c;它们正在蚕食媒体 The games business has lesso…

计算机网络概论

计算机网络概论 组成 客户端&#xff1a;就像蟹堡王的顾客一样。服务端&#xff1a;类似于蟹堡王的分店。路由器&#xff1a;扮演着转发分店的角色。网络协议&#xff1a;像转发表格一样帮助数据在网络中传输。 计算机网络基础 网络组成部分 主机&#xff1a;客户端和服务端…

AVL树原理以及插入代码讲解(插入操作画图~细节)

原理 AVL 树是一种平衡搜索二叉树&#xff0c;得名于其发明者的名字&#xff08; Adelson-Velskii 以及 Landis&#xff09;。&#xff08;可见名字长的好处&#xff0c;命名都能多占一个字母出来&#xff09;。在搜索树的前提下平衡搜索二叉树还定义如下&#xff1a; 左右子…

JVM知识点梳理

什么是JVM&#xff1f; JVM是java虚拟机的缩写 &#xff0c;也是java程式可以实现跨平台的关键。 JVM部分需要知道什么东西&#xff1f; JVM的结构和功能、参数配置、GC回收机制、GC回收器极其优缺点。 JVM结构&#xff08;栈&#xff0c;程序计数器&#xff0c;方法区&#xf…

0009-TIPS-SLAB入门与观察

极简&#xff0c;但是能快速上手 slub算法 这篇文章简洁直观&#xff0c;推荐 linux 内核 内存管理 slub算法 &#xff08;一&#xff09; 原理 感受slub堆漏洞 需要下载 https://github.com/De4dCr0w/green-dill &#xff0c;使用其中的测试程序做实验 UAF 如果看完上面链…