当前位置: 首页 > article >正文

c/c++的opencv像素级操作二值化

图像级操作:使用 C/C++ 进行二值化

在数字图像处理中,图像级操作 (Image-Level Operations) 是指直接在图像的像素级别上进行处理,以改变图像的视觉特性或提取有用信息。这些操作通常不依赖于图像的全局结构,而是关注每个像素及其邻域。一个常见且基础的图像级操作是二值化 (Binarization)
像素级操作是对图像处理的基础


什么是二值化? 🤔

二值化是将灰度图像转换为二值图像的过程。在二值图像中,每个像素只有两种可能的颜色值,通常是黑色和白色(或0和255)。这个过程通过选择一个阈值 (Threshold) 来实现。

  • 如果像素的灰度值 大于 阈值,则将其设置为白色(例如255)。
  • 如果像素的灰度值 小于或等于 阈值,则将其设置为黑色(例如0)。

二值化在许多图像处理应用中非常有用,例如:

  • 对象分割:将感兴趣的对象与背景分离。
  • 文本识别 (OCR):增强文本字符的对比度,使其更容易被识别。
  • 特征提取:简化图像,以便更容易提取形状、轮廓等特征。
  • 图像压缩:减少图像数据量。

如何选择阈值? 🎯

阈值的选择对二值化的结果至关重要。常见的阈值选择方法有:

  • 全局阈值 (Global Thresholding):对整个图像使用单个固定的阈值。这种方法简单快捷,但在光照不均匀的图像中效果可能不佳。
  • 自适应阈值 (Adaptive Thresholding):根据图像不同区域的局部特性计算不同的阈值。这种方法对于光照变化或背景复杂的图像更为有效。常见的自适应阈值算法有均值法和高斯法。
  • Otsu 阈值法 (Otsu’s Method):一种自动确定最佳全局阈值的方法,它试图最大化类间方差(前景和背景之间的方差)。

使用 C/C++ 实现图像二值化 💻

我们将使用 OpenCV (Open Source Computer Vision Library) 这个强大的开源库来演示如何在 C/C++ 中进行图像二值化。OpenCV 提供了丰富的图像处理函数,使得操作更加便捷。

前提条件:

  • 安装了 C++ 编译器 (如 GCC, MSVC)。
  • 安装了 OpenCV 库并配置好了编译环境。

示例代码 (使用全局阈值):

#include <opencv2/opencv.hpp>
#include <iostream>int main(int argc, char** argv) {// 检查输入参数if (argc != 3) {std::cerr << "用法: " << argv[0] << " <输入图像路径> <输出图像路径>" << std::endl;return -1;}// 读取输入图像cv::Mat image = cv::imread(argv[1], cv::IMREAD_GRAYSCALE); // 以灰度模式读取if (image.empty()) {std::cerr << "错误: 无法加载图像 " << argv[1] << std::endl;return -1;}// 定义阈值double threshold_value = 128.0; // 可以根据需要调整double max_binary_value = 255.0;// 创建输出图像cv::Mat binary_image;// 进行二值化操作// cv::THRESH_BINARY: 如果 src(x,y) > thresh, dst(x,y) = maxval; 否则, dst(x,y) = 0.// cv::THRESH_BINARY_INV: 如果 src(x,y) > thresh, dst(x,y) = 0; 否则, dst(x,y) = maxval.cv::threshold(image, binary_image, threshold_value, max_binary_value, cv::THRESH_BINARY);// 保存输出图像if (!cv::imwrite(argv[2], binary_image)) {std::cerr << "错误: 无法保存图像 " << argv[2] << std::endl;return -1;}std::cout << "图像二值化完成!输出图像已保存至: " << argv[2] << std::endl;// (可选) 显示图像// cv::imshow("原始图像", image);// cv::imshow("二值化图像", binary_image);// cv::waitKey(0); // 等待按键return 0;
}

编译和运行 (以 GCC 和 Linux 为例):

假设你的 OpenCV 安装在标准路径下。

  1. 编译:

    g++ -o binarize_image binarize_image.cpp `pkg-config --cflags --libs opencv4`
    

    (如果你的 OpenCV 版本不同,将 opencv4 替换为你的版本,例如 opencv)

  2. 运行:

    ./binarize_image input.jpg output_binary.jpg
    

    确保 input.jpg 存在于当前目录,或者提供完整路径。

代码解释:

  1. #include <opencv2/opencv.hpp>: 包含了 OpenCV 的主要头文件。
  2. cv::imread(argv[1], cv::IMREAD_GRAYSCALE): 读取指定路径的图像。cv::IMREAD_GRAYSCALE 参数确保图像以灰度格式加载,这对于二值化是必需的。
  3. cv::Mat image: cv::Mat 是 OpenCV 中用于存储图像数据的核心类。
  4. double threshold_value = 128.0;: 设置一个固定的全局阈值。通常灰度值范围是 0-255,所以 128 是一个常见的中点。
  5. double max_binary_value = 255.0;: 设置二值化后的最大像素值(通常是白色)。
  6. cv::threshold(image, binary_image, threshold_value, max_binary_value, cv::THRESH_BINARY);: 这是执行二值化的核心函数。
    • image: 输入的灰度图像。
    • binary_image: 输出的二值图像。
    • threshold_value: 设定的阈值。
    • max_binary_value: 当像素值大于阈值时设置的值。
    • cv::THRESH_BINARY: 二值化的类型。还有其他类型,如 cv::THRESH_BINARY_INV (反向二值化), cv::THRESH_TRUNC, cv::THRESH_TOZERO, cv::THRESH_TOZERO_INV
  7. cv::imwrite(argv[2], binary_image): 将处理后的二值图像保存到指定路径。
  8. cv::imshow()cv::waitKey(): (可选) 用于在窗口中显示原始图像和处理后的图像。

使用自适应阈值

对于光照不均的图像,自适应阈值通常效果更好。OpenCV 提供了 cv::adaptiveThreshold 函数。

示例代码片段 (自适应阈值):

#include <opencv2/opencv.hpp>
#include <iostream>int main(int argc, char** argv) {// ... (与前面相同的图像加载和参数检查代码) ...cv::Mat image = cv::imread(argv[1], cv::IMREAD_GRAYSCALE);if (image.empty()) { /* ... */ return -1; }cv::Mat adaptive_binary_image;double max_binary_value = 255.0;int block_size = 11; // 计算阈值的邻域大小,必须是奇数double C = 2;        // 从均值或加权均值中减去的常数// cv::ADAPTIVE_THRESH_MEAN_C: 邻域均值减去 C 作为阈值// cv::ADAPTIVE_THRESH_GAUSSIAN_C: 邻域高斯加权和减去 C 作为阈值cv::adaptiveThreshold(image,adaptive_binary_image,max_binary_value,cv::ADAPTIVE_THRESH_MEAN_C, // 或 cv::ADAPTIVE_THRESH_GAUSSIAN_Ccv::THRESH_BINARY,block_size,C);if (!cv::imwrite(argv[2], adaptive_binary_image)) { /* ... */ return -1; }std::cout << "自适应二值化完成!输出图像已保存至: " << argv[2] << std::endl;return 0;
}

自适应阈值参数:

  • adaptiveMethod: cv::ADAPTIVE_THRESH_MEAN_Ccv::ADAPTIVE_THRESH_GAUSSIAN_C
  • thresholdType: 通常是 cv::THRESH_BINARYcv::THRESH_BINARY_INV
  • blockSize: 用于计算局部阈值的邻域大小。它必须是奇数。
  • C: 一个常数,从计算出的均值或加权均值中减去。这个值可以帮助微调阈值。

不使用 OpenCV (纯 C/C++ 概念)

如果不依赖像 OpenCV 这样的库,你需要自己处理图像文件的读取(例如 BMP、JPEG、PNG 等格式,这本身就很复杂)和像素数据的操作。

以下是一个高度简化的伪代码概念,假设你已经有了一个二维数组表示的灰度图像像素数据 (unsigned char** pixels, int width, int height):

// 伪代码 - 假设像素数据已加载到 unsigned char** pixels
// pixels[row][col] 是 (0-255) 的灰度值void binarize_manual(unsigned char** pixels, int width, int height, unsigned char threshold) {for (int i = 0; i < height; ++i) {for (int j = 0; j < width; ++j) {if (pixels[i][j] > threshold) {pixels[i][j] = 255; // 白色} else {pixels[i][j] = 0;   // 黑色}}}
}// 主要挑战在于如何从文件加载像素数据到 'pixels' 数组
// 以及如何将处理后的 'pixels' 数组保存回图像文件。
// 这通常需要解析图像文件头和像素数据,非常繁琐。

手动实现图像文件I/O的复杂性是使用 OpenCV 等库的主要原因之一。 这些库封装了文件格式的复杂性,并提供了优化的图像处理算法。


总结 ✨

图像二值化是一种基础但非常强大的图像级操作。通过选择合适的阈值方法(全局或自适应),可以将灰度图像转换为对比鲜明的黑白图像,为后续的图像分析和处理步骤奠定基础。使用像 OpenCV 这样的库可以大大简化 C/C++ 中的图像处理任务。

希望这篇文章能帮助你理解图像二值化及其在 C/C++ 中的实现!

相关文章:

c/c++的opencv像素级操作二值化

图像级操作&#xff1a;使用 C/C 进行二值化 在数字图像处理中&#xff0c;图像级操作 (Image-Level Operations) 是指直接在图像的像素级别上进行处理&#xff0c;以改变图像的视觉特性或提取有用信息。这些操作通常不依赖于图像的全局结构&#xff0c;而是关注每个像素及其邻…...

C++----Vector的模拟实现

上一节讲了string的模拟实现&#xff0c;string的出现时间比vector靠前&#xff0c;所以一些函数给的也比较冗余&#xff0c;而后来的vector、list等在此基础上做了优化。这节讲一讲vector的模拟实现&#xff0c;vector与模板具有联系&#xff0c;而string的底层就是vector的一…...

Mac redis下载和安装

目录 1、官网&#xff1a;https://redis.io/ 2、滑到最底下 3、下载资源 4、安装&#xff1a; 5、输入 sudo make test 进行编译测试 会提示 ​编辑 6、sudo make install 继续 7、输入 src/redis-server 启动服务器 8、输入 src/redis-cli 启动测试端 1、官网&#xff…...

[25-cv-05718]BSF律所代理潮流品牌KAWS公仔(商标+版权)

潮流品牌KAWS公仔 案件号&#xff1a;25-cv-05718 立案时间&#xff1a;2025年5月21日 原告&#xff1a;KAWS, INC. 代理律所&#xff1a;Boies Schiller Flexner LLP 原告介绍 原告是一家由美国街头艺术家Brian Donnelly创立的公司&#xff0c;成立于2002年2月25日&…...

【PhysUnits】9 取负重载(negation.rs)

一、源码 这段代码是类型级二进制数&#xff08;包括正数和负数&#xff09;的取反和取负操作。它使用了类型系统来表示二进制数&#xff0c;并通过特质&#xff08;trait&#xff09;和泛型来实现递归操作。 use super::basic::{B0, B1, Z0, N1}; use core::ops::Neg;// 反…...

深度思考、弹性实施,业务流程自动化的实践指南

随着市场环境愈发复杂化&#xff0c;各类型企业的业务步伐为了跟得上市场节奏也逐步变得紧张&#xff0c;似乎只有保持极强的竞争力、削减成本、提升抗压能力才能在市场洪流中博得一席之位。此刻企业需要制定更明智的解决方案&#xff0c;以更快、更准确地优化决策流程。与简单…...

UWB:litepoint获取txquality里面的NRMSE

在使用litepoint测试UWB,获取txquality里面的NRMSE时,网页端可以正常获取NRMSE。但是通过SCPI 命令来获取NRMSE一直出错。 NRMSE数据类型和pyvisa问题: 参考了user guide,发现NRMSE的数值是ARBITRARY_BLOCK FLOAT,非string。 pyvisa无法解析会返回错误。 查询了各种办法…...

VUE npm ERR! code ERESOLVE, npm ERR! ERESOLVE could not resolve, 错误有效解决

VUE &#xff1a; npm ERR! code ERESOLVE npm ERR! ERESOLVE could not resolve 错误有效解决 npm install 安装组件的时候出现以上问题&#xff0c;npm版本问题报错解决方法&#xff1a;用上述方法安装完成之后又出现其他的问题 npm install 安装组件的时候出现以上问题&…...

IoT/HCIP实验-1/物联网开发平台实验Part1(快速入门,MQTT.fx对接IoTDA)

文章目录 实验介绍设备接入IoTDA进入IoTDA平台什么是IoTDA 开通服务创建产品和设备定义产品模型&#xff08;Profile&#xff09;设备注册简思(实例-产品-设备) 模拟.与平台通信虚拟设备/MQTT.fx应用 Web 控制台QA用户或密码错误QA证书导致的连接失败设备与平台连接成功 上报数…...

DMA STM32H7 Domains and space distrubution

DMA这个数据搬运工&#xff0c;对谁都好&#xff0c;任劳任怨&#xff0c;接受雇主设备的数据搬运业务。每天都忙碌着&#xff01;哈哈哈。 1. DMA 不可能单独工作&#xff0c;必须接收其他雇主的业务&#xff0c;所以数据搬运业务的参与者是DMA本身和业务需求发起者。 2. 一…...

洪水危险性评价与风险防控全攻略:从HEC-RAS数值模拟到ArcGIS水文分析,一键式自动化工具实战,助力防洪减灾与应急管理

&#x1f50d; 洪水淹没危险性是洪水损失评估、风险评估及洪水应急和管理规划等工作的重要基础。当前&#xff0c;我国正在开展的自然灾害风险普查工作&#xff0c;对洪水灾害给予了重点关注&#xff0c;提出了对洪水灾害危险性及风险评估的明确要求。洪水危险性及风险评估通常…...

Gemini Pro 2.5 输出

好的&#xff0c;我已经按照您的要求&#xff0c;将顶部横幅提示消息修改为右下角的 Toast 样式通知。 以下是涉及更改的文件及其内容&#xff1a; 1. my/src/html-ui.js 移除了旧的 #message-area div。在 <body> 底部添加了新的 #toast-container div 用于存放 Toas…...

SQL Server 和 MySQL 对比

下面是 SQL Server 和 MySQL 的详细对比&#xff0c;从功能、性能、成本、生态等多个维度展开&#xff0c;帮助你判断在什么情况下该选择哪一个。 ✅ 总览对比表 维度SQL ServerMySQL开发公司微软&#xff08;Microsoft&#xff09;Oracle&#xff08;2008年起&#xff09;是否…...

Leetcode 3269. 构建两个递增数组

1.题目基本信息 1.1.题目描述 给定两个只包含 0 和 1 的整数数组 nums1 和 nums2&#xff0c;你的任务是执行下面操作后使数组 nums1 和 nums2 中 最大 可达数字 尽可能小。 将每个 0 替换为正偶数&#xff0c;将每个 1 替换为正奇数。在替换后&#xff0c;两个数组都应该 递…...

三轴云台之积分分离PID控制算法篇

一、核心原理 积分分离PID控制的核心在于动态调整积分项的作用&#xff0c;以解决传统PID在三轴云台应用中的超调、振荡问题&#xff1a; 大误差阶段&#xff08;如云台启动或快速调整时&#xff09;&#xff1a; 关闭积分项&#xff0c;仅使用比例&#xff08;P&#xff09;…...

【Elasticsearch】scripted_upsert

在 Elasticsearch 中&#xff0c;scripted_upsert 是一个用于更新操作的参数&#xff0c;它允许在文档不存在时通过脚本初始化文档内容&#xff0c;而不是直接使用 upsert 部分的内容。这种方式提供了更灵活的文档创建和更新逻辑。 scripted_upsert 的工作原理 当设置 scripte…...

uv - 一个现代化的项目+环境管理工具

参考&#xff1a; 【uv】Python迄今最好的项目管理环境管理工具&#xff08;吧&#xff1f;&#xff09;_哔哩哔哩_bilibili 项目需求 想象&#xff0c;每次创建一个项目的时候&#xff0c;我们需要去写 README. md, .git 仓库, .gitignore&#xff0c;你会感觉很头大 对于 …...

经典密码学和现代密码学的结构及其主要区别(2)维吉尼亚密码—附py代码

Vigenre cipher 维吉尼亚密码 维吉尼亚密码由布莱斯德维吉尼亚在 16 世纪发明&#xff0c;是凯撒密码的一个更复杂的扩展。它是一种多字母替换密码&#xff0c;使用一个关键字来确定明文中不同字母的多个移位值。 与凯撒密码不同&#xff0c;凯撒密码对所有字母都有固定的偏移…...

Elasticsearch 节点角色详解及协调节点请求策略

引言 Elasticsearch 集群中的节点可以承担多种角色&#xff0c;如主节点、数据节点、预处理节点和协调节点。合理配置和理解这些节点角色&#xff0c;对于保障集群的高可用性、性能优化以及请求调度至关重要。本文将深入解析各类节点的职责与配置方式&#xff0c;并介绍如何通…...

视频逐帧提取图片的工具

软件功能&#xff1a;可以将视频逐帧提取图片&#xff0c;可以设置每秒提取多少帧&#xff0c;选择提取图片质量测试环境&#xff1a;Windows 10软件设置&#xff1a;由于软件需要通过FFmpeg提取图片&#xff0c;运行软件前请先设置FFmpeg&#xff0c;具体步骤 1. 请将…...

数据结构第1章编程基础 (竟成)

第 1 章 编程基础 1.1 前言 因为数据结构的代码大多采用 C 语言进行描述。而且&#xff0c;408 考试每年都有一道分值为 13 - 15 的编程题&#xff0c;要求使用 C/C 语言编写代码。所以&#xff0c;本书专门用一章来介绍 408 考试所需的 C/C 基础知识。有基础的考生可以快速浏览…...

互联网大厂Java求职面试:AI大模型与云原生架构融合中的挑战

互联网大厂Java求职面试&#xff1a;AI大模型与云原生架构融合中的挑战 在互联网大厂的Java求职面试中&#xff0c;面试官往往以技术总监的身份&#xff0c;针对候选人对AI、大模型应用集成、云原生和低代码等新兴技术的理解与实践能力进行考察。以下是一个典型的面试场景&…...

msql的乐观锁和幂等性问题解决方案

目录 1、介绍 2、乐观锁 2.1、核心思想 2.2、实现方式 1. 使用 version 字段&#xff08;推荐&#xff09; 2. 使用 timestamp 字段 2.3、如何处理冲突 2.4、乐观锁局限性 3、幂等性 3.1、什么是幂等性 3.2、乐观锁与幂等性的关系 1. 乐观锁如何辅助幂等性&#xf…...

Python 实现桶排序详解

1. 核心原理 桶排序是一种非比较型排序算法&#xff0c;通过将数据分配到多个“桶”中&#xff0c;每个桶单独排序后再合并。其核心步骤包括&#xff1a; 分桶&#xff1a;根据元素的范围或分布&#xff0c;将数据分配到有限数量的桶中。桶内排序&#xff1a;对每个非空桶内的…...

大模型(5)——编码器(Encoder)、解码器(Decoder)

文章目录 一、编码器&#xff08;Encoder&#xff09;1. 核心作用2. 典型结构&#xff08;以Transformer为例&#xff09;3. 应用场景 二、解码器&#xff08;Decoder&#xff09;1. 核心作用2. 典型结构&#xff08;以Transformer为例&#xff09;3. 应用场景 三、编码器与解码…...

Web3怎么本地测试连接以太坊?

ETHEREUM_RPC_URLhttps://sepolia.infura.io/v3/你的_INFURA_API_KEY 如果你没有 Infura Key&#xff0c;注册 Infura 或 Alchemy&#xff0c;拿一个免费测试网节点就行&#xff1a; Infura&#xff1a;https://infura.io Alchemy&#xff1a;Alchemy - the web3 developme…...

Vue-02 (使用不同的 Vue CLI 插件)

使用不同的 Vue CLI 插件 Vue CLI 插件扩展了 Vue 项目的功能&#xff0c;让你可以轻松集成 TypeScript、Vuex、路由等功能。它们可以自动进行配置和设置&#xff0c;从而节省您的时间和精力。了解如何使用这些插件对于高效的 Vue 开发至关重要。 了解 Vue CLI 插件 Vue CLI…...

理解vue-cli 中进行构建优化

在 Vue CLI 项目中进行构建优化&#xff0c;是前端性能提升的重要手段。它涉及到 Webpack 配置、代码分包、懒加载、依赖优化、图片压缩等多个方面。 &#x1f9f1; 基础构建优化 设置生产环境变量 NODE_ENVproduction Vue CLI 会自动在 npm run build 时开启以下优化&…...

理解计算机系统_线程(九):线程安全问题

前言 以<深入理解计算机系统>(以下称“本书”)内容为基础&#xff0c;对程序的整个过程进行梳理。本书内容对整个计算机系统做了系统性导引,每部分内容都是单独的一门课.学习深度根据自己需要来定 引入 接续理解计算机系统_线程(八):并行-CSDN博客,内容包括12.7…...

vue3基本类型和对象类型的响应式数据

vue3中基本类型和对象类型的响应式数据 OptionsAPI与CompstitionAPI的区别 OptionsAPI Options API • 特点&#xff1a;基于选项&#xff08;options&#xff09;来组织代码&#xff0c;将逻辑按照生命周期、数据、方法等分类。• 结构&#xff1a;代码按照 data 、 methods…...