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

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.图像区域分割与提取

&#xff08;1&#xff09;创建一个名为SplitImage的窗体的应用程序&#xff0c;将窗体改名为FormSplitImage。 &#xff08;2&#xff09;创建一个名为ImageProcessingLibrary的类库程序&#xff0c;为该工程添加名为ImageProcessing的静态类 &#xff08;3&#xff09;为Imag…...

炸弹使用技巧

掼蛋掼蛋&#xff0c;打的就是炸弹。炸弹是指掼蛋中由4-8张相同牌点的牌组成的牌型&#xff0c;需要注意的是&#xff1a;每局牌中都有两张红桃的牌型为逢人配&#xff0c;可以配除了大小王以外的任意牌&#xff0c;因此掼蛋中牌数最多的炸弹可以达到10张。 两副扑克牌中&#…...

SpringAop详解

文章目录 一、Spring自定义注解1、什么是注解&#x1f468;‍&#x1f3eb;2、注解的目的或作用&#x1f49e;3、JDK内置注解&#x1f4ab; 【内置元注解 一共八个固定注解】4、元注解 &#x1f3af;5、自定义注解&#x1f4f8;5、Java反射API和类加载过程51、什么是反射基本原…...

对XYctf的一些总结

对XYctf的一些总结 WEB 1.http请求头字段 此次比赛中出现的&#xff1a; X-Forwarded-For/Client-ip&#xff1a;修改来源ip via&#xff1a;修改代理服务器 还有一些常见的字段&#xff1a; GET&#xff1a;此方法用于请求指定的资源。GET请求应该安全且幂等&#xff0c…...

Visual Studio和Visual Studio Code适用于哪些编程语言

Visual Studio和Visual Studio Code都适用于多种编程语言&#xff0c;它们的适用编程语言如下&#xff1a; Visual Studio适用于&#xff1a; C#Visual Basic .NETF#CJavaScriptTypeScriptPythonHTML/CSSJava&#xff08;通过插件支持&#xff09; Visual Studio Code适用于…...

缓存菜品操作

一&#xff1a;问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得&#xff0c;如果用户端访问量比较大&#xff0c;数据库访问压力随之增大。 二&#xff1a;实现思路 通过Redis来缓存菜品数据&#xff0c;减少数据库查询操作。 缓存逻辑分析&#xff1a; 每个分…...

达梦数据库常用命令整理

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 组件通常由三大组成部分构成&#xff1a;模板&#xff08;Template&#xff09;、脚本&#xff08;Script&#xff09;、样式&#xff08;Style&#xff09; 模板部分是组件的 HTML 结构&#xff0c;它定义了组件的外观和布局。Vue 使用基于 HTML 的模板语法来声明组件的模…...

MoneyPrinter中的文字转声音国内替换方案

背景&#xff1a; 在进行MoneyPrinter项目国内环境搭建中&#xff0c;发现框架本身的TikTok文字转语音部分的代码已经不能用了&#xff0c;最好是能够找到国内网站的替换方案。 实现&#xff1a; 感谢网站&#xff1a;https://www.text-to-speech.cn/ 代码&#xff1a; # -*…...

消除试卷手写笔迹的软件免费的有哪些?这几款都不错

消除试卷手写笔迹的软件免费的有哪些&#xff1f;在数字化学习的浪潮中&#xff0c;学生们越来越频繁地利用电子设备来完成学习任务。然而&#xff0c;当纸质试卷需要被数字化并再次利用时&#xff0c;如何高效地消除手写笔迹便成为了一个有待解决的问题。那么&#xff0c;今天…...

智能创作时代:AI 如何重塑内容生成游戏规则

文章目录 前言一&#xff1a;自动化内容生成文章生成视频制作音频创作 二&#xff1a;内容分发与推广智能推荐系统社交媒体优化 三&#xff1a;内容分析与优化数据分析用户反馈质量控制 结语 前言 在数字化时代的浪潮中&#xff0c;内容生产与消费已成为信息传播的核心。随着人…...

大数据------JavaWeb------Tomcat(完整知识点汇总)

Web服务器——Tomcat Web服务器定义 它是一个应用程序&#xff08;软件&#xff09;&#xff0c;对HTTP协议的操作进行封装&#xff0c;使得程序员不必直接对协议进行操作&#xff0c;让Web开发更便捷 Web服务器主要功能 封装HTTP协议操作&#xff0c;简化开发将Web项目部署到…...

LMDeploy笔记

随谈模型部署 模型部署包含的内容很多&#xff0c;来聊聊。 访存bottleneck 首先&#xff0c;基于transformer的计算是访存密集型任务。 so? 过去&#xff0c;我们表达模型的性能&#xff0c;通常会用ops&#xff0c;macs这些指标,也计算量来衡量模型的推理时间&#xff…...

Unity 状态机

文章目录 前言一、状态机二、应用1、场景切换2、人物行为切换3、宝箱、机关切换4、AI 三、人物行为总结 前言 提到Unity状态机&#xff0c;接触不久的开发者会想到Unity的动画状态机&#xff0c;而对于老油条来说&#xff0c;可能会回忆起自己实现的动画状态机。当然&#xff…...

一毛钱不到的FH8208C单节锂离子和锂聚合物电池一体保护芯片

前言 目前市场上电池保护板&#xff0c;多为分体方案&#xff0c;多数场合使用没有问题&#xff0c;部分场合对空间有进一步要求&#xff0c;或者你不想用那么多器件&#xff0c;想精简一些&#xff0c;那么这个芯片就很合适&#xff0c;对于充电电池来说&#xff0c;应在使用…...

python数据可视化:显示两个变量间的关系散点图scatterplot()

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 python数据可视化&#xff1a; 显示两个变量间的关系 散点图 scatterplot() [太阳]选择题 请问关于以下代码表述错误的选项是&#xff1f; 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根目录为一个大的分区(支持动态扩容)&#xff0c;事前就根本上解决根目录空间不够问题3.1.0、方法思路3.1.1、docker官网安装文档3.1.2、下载docker安装包3.1.3、安装doc…...

React 项目报错解决办法收录

React 使用 引入文件报错 (react 别名配置craco) react &#xff0c;vue 初始项目都是不支持 别名引入文件的。 vue 一般项目初始化的时候会 在 vue.config.js 文件中配置好&#xff0c;所以不需要我们自己配置react 初始化的时候是没有配置的&#xff0c; 需要我们自己配置 …...

生成xcframework

打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式&#xff0c;可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...

rknn优化教程(二)

文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK&#xff0c;开始写第二篇的内容了。这篇博客主要能写一下&#xff1a; 如何给一些三方库按照xmake方式进行封装&#xff0c;供调用如何按…...

基于ASP.NET+ SQL Server实现(Web)医院信息管理系统

医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上&#xff0c;开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识&#xff0c;在 vs 2017 平台上&#xff0c;进行 ASP.NET 应用程序和简易网站的开发&#xff1b;初步熟悉开发一…...

【入坑系列】TiDB 强制索引在不同库下不生效问题

文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

连锁超市冷库节能解决方案:如何实现超市降本增效

在连锁超市冷库运营中&#xff0c;高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术&#xff0c;实现年省电费15%-60%&#xff0c;且不改动原有装备、安装快捷、…...

vue3 定时器-定义全局方法 vue+ts

1.创建ts文件 路径&#xff1a;src/utils/timer.ts 完整代码&#xff1a; import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...

uniapp中使用aixos 报错

问题&#xff1a; 在uniapp中使用aixos&#xff0c;运行后报如下错误&#xff1a; AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...

QT: `long long` 类型转换为 `QString` 2025.6.5

在 Qt 中&#xff0c;将 long long 类型转换为 QString 可以通过以下两种常用方法实现&#xff1a; 方法 1&#xff1a;使用 QString::number() 直接调用 QString 的静态方法 number()&#xff0c;将数值转换为字符串&#xff1a; long long value 1234567890123456789LL; …...

聊一聊接口测试的意义有哪些?

目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开&#xff0c;首…...

鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南

1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发&#xff0c;使用DevEco Studio作为开发工具&#xff0c;采用Java语言实现&#xff0c;包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...