C#图像:1.图像区域分割与提取
(1)创建一个名为SplitImage的窗体的应用程序,将窗体改名为FormSplitImage。

(2)创建一个名为ImageProcessingLibrary的类库程序,为该工程添加名为ImageProcessing的静态类
(3)为ImageProcessing类添加统计直方图的静态函数
(4)在ImageProcessing类中添加二值化处理函数BinaryImage
(5)在SplitImage工程中引用ImageProcessingLibrary工程,并添加ImageProcessingLibrary, System.Drawing命名空间。
(6)在窗体中重写OnPaint事件函数,并在函数中添加绘制原始图像、显示直方图和图像分割与提取后的图像
程序框架 :
被窗体的应用程序引用的类库代码:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;namespace ImageProcessingLibrary
{public static class ImageProcessing{/// 获取直方图数组,并绘制直方图/// <param name="image">需要处理的图像</param>/// <param name="indexColor">处理的颜色索引值,Blue:0,Green:1,Red:2</param>/// <param name="histogram">直方图统计数组</param>/// <returns>绘制好的直方图</returns>public static Bitmap GetHistogram(Bitmap image, int indexColor, out int[] histogram){histogram = new int[256]; //直方图统计数组BitmapData data = image.LockBits(new Rectangle(new Point(), image.Size),ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); //将图像锁定到内存中byte[] datas = new byte[data.Stride * image.Height]; //图像数组Marshal.Copy(data.Scan0, datas, 0, datas.Length); //将图像在内存中的数据复制到图像数组中for (int y = 0; y < image.Height * data.Stride; y += data.Stride) //data.Stride代表图像一行数据的字节总数/步长为data.Stride{//外层循环是遍历行for (int x = 0; x < image.Width * 3; x += 3)//遍历当前行中的每个像素/每个像素由三个字节(RGB)组成//每个颜色分量(红色、绿色或蓝色)可以有的不同强度级别就是2^8,即256个级别{int index = y + x; //颜色在内存中的索引/每个索引偏移量3字节(对应R,G,B)histogram[datas[index + indexColor]]++;//增加直方图中对应颜色分量出现的次数}}image.UnlockBits(data);byte maxValue = 0; //直方图中的最大值for (int value = 1; value < 256; value++){if (histogram[value] > histogram[maxValue]) maxValue = (byte)value;}Bitmap imageHistogram = new Bitmap(256, 256);Graphics GHistogram = Graphics.FromImage(imageHistogram);GHistogram.Clear(Color.Blue);for (int value = 1; value< 256; value++){int length = byte.MaxValue * histogram[value] / histogram[maxValue];GHistogram.DrawLine(new Pen(Color.FromArgb(value, value, value), 1f), value,256, value, 256 - length); //绘制直方图}Font font = new Font("宋体", 9f);//绘制统计标识for (int value = 32; value < 256; value += 32){int count = histogram[maxValue] / 8 * value / 32;Pen pen = new Pen(Color.Lime);pen.DashStyle = DashStyle.DashDot;SizeF sizeCount = GHistogram.MeasureString(count.ToString(), font);GHistogram.DrawLine(pen, 0, 255 - value, 255, 255 - value);//绘制数量等级线GHistogram.DrawString(count.ToString(), font, Brushes.Red, 5, 255 - value - sizeCount.Height / 2);SizeF sizeValue = GHistogram.MeasureString(value.ToString(), font);GHistogram.DrawLine(Pens.Red, value, 250, value, 255);//绘制颜色值等级线GHistogram.DrawString(value.ToString(), font, Brushes.Red, value - sizeValue.Width / 2, 240);}font.Dispose();return imageHistogram;}/// 将图像进行二值化处理/// <param name="image">需要处理的图像</param>/// <param name="indexColor">处理的颜色索引值,Blue:0,Green:1,Red:2</param>/// <param name="thresholdMin">阈值下限</param>/// <param name="thresholdMax">阈值上限</param>public static void BinaryImage(Bitmap image, int indexColor, int thresholdMin, int thresholdMax){//将图像锁定到内存中BitmapData data = image.LockBits(new Rectangle(new Point(), image.Size), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);byte[] datas = new byte[data.Stride * image.Height]; //图像数组Marshal.Copy(data.Scan0, datas, 0, datas.Length); //将图像在内存中的数据复制到图像数组中for (int y = 0; y < image.Height * data.Stride; y += data.Stride){for (int x = 0; x < image.Width * 3; x += 3){int index = y + x;//根据阈值将图像分成黑色和白色,其中阈值内的为黑色,阈值外的为白色if (datas[index + indexColor] >= thresholdMin && datas[index + indexColor] <= thresholdMax)datas[index] = datas[index + 1] = datas[index + 2] = 0;elsedatas[index] = datas[index + 1] = datas[index + 2] = 255;}}Marshal.Copy(datas, 0, data.Scan0, datas.Length); //将图像数组复制到内存中image.UnlockBits(data); //将图像从内存中解锁}}}
/*假设颜色分量是8位的,那么每个颜色分量(红色、绿色或蓝色)可以有的不同强度级别就是2^8,即256个级别。* 这是因为8位可以表示从0到255的整数,总共256个不同的数值。在数字图像处理中,8位颜色深度是常见的,* 因为它提供了足够的动态范围来表示大多数自然和人工颜色的细微差别,同时保持数据量相对较小。当你说“直方图大小为256”时,你指的是直方图的横坐标(即颜色强度的可能值)有256个不同的条目,
每个条目对应一个特定的颜色强度值(从0到255)。直方图的纵坐标通常表示该颜色强度值在图像中出现的频率或像素数量。因此,如果我们想为8位颜色分量的图像构建直方图,我们将创建一个大小为256的数组,数组的每个元素初始化为0。
然后,我们遍历图像的每个像素,对于每个像素的特定颜色分量(如红色、绿色或蓝色),我们增加直方图中对应颜色强度值的计数。
这个过程最终会给我们一个表示图像中每个颜色强度出现频率的直方图。*/
窗体的应用程序,重写OnPaint事件函数代码:
using ImageProcessingLibrary;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;namespace SplitImage
{public partial class FormSplitImage : Form{public FormSplitImage(){InitializeComponent();}protected override void OnPaint(PaintEventArgs e)//重写OnPaint事件函数{Graphics G = e.Graphics;Bitmap image = new Bitmap("123456.jpg"); //加载图像Rectangle rectImage = new Rectangle(new Point(), image.Size);G.DrawImage(image, rectImage); //绘制原始图像int[] histogram; //直方图统计数组Rectangle rectHistogram = new Rectangle(rectImage.Width, 0, 256, 256); //获取图像的灰度直方图(起始点X,Y,像素大小x,y)Bitmap imageHistogram = ImageProcessing.GetHistogram(image, 0, out histogram);//这里out返回了直方图数组histogramG.DrawImage(imageHistogram, rectHistogram); //绘制直方图rectImage.Offset(0, image.Height);//矩形位置调整指定的量,即往下(y)移一个图片高度,定义了绘制分割后的图像的rectImageImageProcessing.BinaryImage(image, 1, 0, 150); //通过二值化将目标分割出来()G.DrawImage(image, rectImage); //绘制分割后的图像image.Dispose(); //释放图像imageHistogram.Dispose(); //释放直方图图像}}
}
在程序路径下准备图片:123456.jpg

运行SplitImage窗体的应用程序:

相关文章:
C#图像:1.图像区域分割与提取
(1)创建一个名为SplitImage的窗体的应用程序,将窗体改名为FormSplitImage。 (2)创建一个名为ImageProcessingLibrary的类库程序,为该工程添加名为ImageProcessing的静态类 (3)为Imag…...
炸弹使用技巧
掼蛋掼蛋,打的就是炸弹。炸弹是指掼蛋中由4-8张相同牌点的牌组成的牌型,需要注意的是:每局牌中都有两张红桃的牌型为逢人配,可以配除了大小王以外的任意牌,因此掼蛋中牌数最多的炸弹可以达到10张。 两副扑克牌中&#…...
SpringAop详解
文章目录 一、Spring自定义注解1、什么是注解👨🏫2、注解的目的或作用💞3、JDK内置注解💫 【内置元注解 一共八个固定注解】4、元注解 🎯5、自定义注解📸5、Java反射API和类加载过程51、什么是反射基本原…...
对XYctf的一些总结
对XYctf的一些总结 WEB 1.http请求头字段 此次比赛中出现的: X-Forwarded-For/Client-ip:修改来源ip via:修改代理服务器 还有一些常见的字段: GET:此方法用于请求指定的资源。GET请求应该安全且幂等,…...
Visual Studio和Visual Studio Code适用于哪些编程语言
Visual Studio和Visual Studio Code都适用于多种编程语言,它们的适用编程语言如下: Visual Studio适用于: C#Visual Basic .NETF#CJavaScriptTypeScriptPythonHTML/CSSJava(通过插件支持) Visual Studio Code适用于…...
缓存菜品操作
一:问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大。 二:实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: 每个分…...
达梦数据库常用命令整理
1.数据库自身信息 1.1 查询实例信息 SQL> select name inst_name from v$instance;行号 INST_NAME ---------- --------- 1 DMSERVER已用时间: 11.211(毫秒). 执行号:15.1.2 查询数据库当前状态 SQL> select status$ from v$instance;行号 STATUS$ -…...
Vue 组件的三大组成部分
Vue 组件通常由三大组成部分构成:模板(Template)、脚本(Script)、样式(Style) 模板部分是组件的 HTML 结构,它定义了组件的外观和布局。Vue 使用基于 HTML 的模板语法来声明组件的模…...
MoneyPrinter中的文字转声音国内替换方案
背景: 在进行MoneyPrinter项目国内环境搭建中,发现框架本身的TikTok文字转语音部分的代码已经不能用了,最好是能够找到国内网站的替换方案。 实现: 感谢网站:https://www.text-to-speech.cn/ 代码: # -*…...
消除试卷手写笔迹的软件免费的有哪些?这几款都不错
消除试卷手写笔迹的软件免费的有哪些?在数字化学习的浪潮中,学生们越来越频繁地利用电子设备来完成学习任务。然而,当纸质试卷需要被数字化并再次利用时,如何高效地消除手写笔迹便成为了一个有待解决的问题。那么,今天…...
智能创作时代:AI 如何重塑内容生成游戏规则
文章目录 前言一:自动化内容生成文章生成视频制作音频创作 二:内容分发与推广智能推荐系统社交媒体优化 三:内容分析与优化数据分析用户反馈质量控制 结语 前言 在数字化时代的浪潮中,内容生产与消费已成为信息传播的核心。随着人…...
大数据------JavaWeb------Tomcat(完整知识点汇总)
Web服务器——Tomcat Web服务器定义 它是一个应用程序(软件),对HTTP协议的操作进行封装,使得程序员不必直接对协议进行操作,让Web开发更便捷 Web服务器主要功能 封装HTTP协议操作,简化开发将Web项目部署到…...
LMDeploy笔记
随谈模型部署 模型部署包含的内容很多,来聊聊。 访存bottleneck 首先,基于transformer的计算是访存密集型任务。 so? 过去,我们表达模型的性能,通常会用ops,macs这些指标,也计算量来衡量模型的推理时间ÿ…...
Unity 状态机
文章目录 前言一、状态机二、应用1、场景切换2、人物行为切换3、宝箱、机关切换4、AI 三、人物行为总结 前言 提到Unity状态机,接触不久的开发者会想到Unity的动画状态机,而对于老油条来说,可能会回忆起自己实现的动画状态机。当然ÿ…...
一毛钱不到的FH8208C单节锂离子和锂聚合物电池一体保护芯片
前言 目前市场上电池保护板,多为分体方案,多数场合使用没有问题,部分场合对空间有进一步要求,或者你不想用那么多器件,想精简一些,那么这个芯片就很合适,对于充电电池来说,应在使用…...
python数据可视化:显示两个变量间的关系散点图scatterplot()
【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 python数据可视化: 显示两个变量间的关系 散点图 scatterplot() [太阳]选择题 请问关于以下代码表述错误的选项是? import seaborn as sns import matplotlib.pyplot …...
【QT教程】QT6硬件高级编程入门 QT硬件高级编程
QT6硬件高级编程入门 使用AI技术辅助生成 QT界面美化视频课程 QT性能优化视频课程 QT原理与源码分析视频课程 QT QML C扩展开发视频课程 免费QT视频课程 您可以看免费1000个QT技术视频 免费QT视频课程 QT统计图和QT数据可视化视频免费看 免费QT视频课程 QT性能优化视频免费看…...
Android 蓝牙实战——蓝牙电话通话状态同步(二十四)
前面分析了蓝牙电话通话状态的广播,我们可以在蓝牙电话中实时监听蓝牙电话的状态,但如果是其他音乐类 APP 呢,在播放的时候也需要知道当前是否有通话正在进行,但是有完全没必要实时监听电话的状态,这就需要一个获取通话状态的方法。 一、通话状态处理 1、CallsManager …...
docker 指定根目录 迁移根目录
docker 指定根目录 迁移根目录 1、问题描述2、问题分析3、解决方法3.1、启动docker程序前就手动指定docker根目录为一个大的分区(支持动态扩容),事前就根本上解决根目录空间不够问题3.1.0、方法思路3.1.1、docker官网安装文档3.1.2、下载docker安装包3.1.3、安装doc…...
React 项目报错解决办法收录
React 使用 引入文件报错 (react 别名配置craco) react ,vue 初始项目都是不支持 别名引入文件的。 vue 一般项目初始化的时候会 在 vue.config.js 文件中配置好,所以不需要我们自己配置react 初始化的时候是没有配置的, 需要我们自己配置 …...
未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?
编辑:陈萍萍的公主一点人工一点智能 未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战,在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...
MongoDB学习和应用(高效的非关系型数据库)
一丶 MongoDB简介 对于社交类软件的功能,我们需要对它的功能特点进行分析: 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具: mysql:关系型数据库&am…...
Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...
微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...
k8s业务程序联调工具-KtConnect
概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...
select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。 一、I…...
React---day11
14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store: 我们在使用异步的时候理应是要使用中间件的,但是configureStore 已经自动集成了 redux-thunk,注意action里面要返回函数 import { configureS…...
AGain DB和倍数增益的关系
我在设置一款索尼CMOS芯片时,Again增益0db变化为6DB,画面的变化只有2倍DN的增益,比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析: 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...
Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换
目录 关键点 技术实现1 技术实现2 摘要: 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式(自动驾驶、人工驾驶、远程驾驶、主动安全),并通过实时消息推送更新车…...
