C#数字图像处理(十四)击中击不中变换 (Hit-miss)
击中击不中变换定义
击中击不中变换(HMT)需要两个结构元素B1和B2,合成一个结构元素对B=(B1,B2)
一个用于探测图像内部,作为击中部分;另一个用于探测图像外部,作为击不中部分。显然,B1和B2是不应该相连接的,即B1∩B2=Φ。击中击不中变换的数学表达式为:
g(x, y)=hitmiss[f(x, y), B]=erode[f(x, y), B1]AND erode[fc(x, y), B2]
其中,fc(x,y)表示的是f(x,y)的补集。
Hit-miss算法步骤:
击中击不中变换是形态学中用来检测特定形状所处位置的一个基本工具。它的原理就是使用腐蚀;如果要在一幅图像A上找到B形状的目标,我们要做的是:
首先,建立一个比B大的模板W;使用此模板对图像A进行腐蚀,得到图像假设为Process1;
其次,用B减去W,从而得到V模板(W-B);使用V模板对图像A的补集进行腐蚀,得到图像假设为Process2;
然后,Process1与Process2取交集;得到的结果就是B的位置。这里的位置可能不是B的中心位置,要视W-B时对齐的位置而异;
其实很简单,两次腐蚀,然后交集,结果就出来了。
Hit-miss原理:
基于腐蚀运算的一个特性:腐蚀的过程相当于对可以填入结构元素的位置作标记的过程。
腐蚀中,虽然标记点取决于原点在结构元素中的相对位置,但输出图像的形状与此无关,改变原点的位置,只会导致输出结果发生平移。
既然腐蚀的过程相当于对可以填入结构元素的位置作标记的过程,可以利用腐蚀来确定目标的位置。进行目标检测,既要检测到目标的内部,也要检测到外部,即在一次运算中可以同时捕获内外标记。
由于以上两点,采用两个结构基元H、M,作为一个结构元素对B=(H,M),一个探测目标内部,一个探测目标外部。当且仅当H平移到某一点可填入X的内部,M平移到该点可填入X的外部时,该点才在击中击不中变换的输出中。
Hit-miss示意图:
在A图中寻找B图所示的图像目标的位置。
解:
1、确定结构元素
既然是寻找图B所示形状,选取H为图B所示的形状。再选一个小窗口W,W包含H,M=W-H。如下图所示:
2、求
3、求
4、求
/// <summary>
/// 击中击不中:只能处理位深度为8的512*512图像
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void hitMiss_Click(object sender, EventArgs e)
{
if (curBitmap != null)
{
hitmiss hitAndMiss = new hitmiss();
if (hitAndMiss.ShowDialog() == DialogResult.OK)
{
Rectangle rect = new Rectangle(, , curBitmap.Width, curBitmap.Height);
BitmapData bmpData = curBitmap.LockBits(rect, ImageLockMode.ReadWrite, curBitmap.PixelFormat);
IntPtr ptr = bmpData.Scan0;
int bytes = curBitmap.Width * curBitmap.Height;
byte[] grayValues = new byte[bytes];
Marshal.Copy(ptr, grayValues, , bytes); //得到击中结构元素
bool[] hitStru = hitAndMiss.GetHitStruction;
//得到击不中结构元素
bool[] missStru = hitAndMiss.GetMissStruction; byte[] tempArray = new byte[bytes];
byte[] temp1Array = new byte[bytes];
byte[] temp2Array = new byte[bytes];
for (int i = ; i < bytes; i++)
{
//原图补集
tempArray[i] = (byte)( - grayValues[i]);
temp1Array[i] = ;
temp2Array[i] = ;
} //应用击中结构元素进行腐蚀运算
for (int i = ; i < curBitmap.Height - ; i++)
{
for (int j = ; j < curBitmap.Width - ; j++)
{
//当前位置是黑色或者是击中结构元素的这一位置没有选中
if ((grayValues[(i - ) * curBitmap.Width + j - ] == || hitStru[] == false) &&
(grayValues[(i - ) * curBitmap.Width + j] == || hitStru[] == false) &&
(grayValues[(i - ) * curBitmap.Width + j + ] == || hitStru[] == false) &&
(grayValues[i * curBitmap.Width + j - ] == || hitStru[] == false) &&
(grayValues[i * curBitmap.Width + j] == || hitStru[] == false) &&
(grayValues[i * curBitmap.Width + j + ] == || hitStru[] == false) &&
(grayValues[(i + ) * curBitmap.Width + j - ] == || hitStru[] == false) &&
(grayValues[(i + ) * curBitmap.Width + j] == || hitStru[] == false) &&
(grayValues[(i + ) * curBitmap.Width + j + ] == || hitStru[] == false))
{
temp1Array[i * curBitmap.Width + j] = ;
} }
} //应用击不中结构元素进行腐蚀运算
for (int i = ; i < curBitmap.Height - ; i++)
{
for (int j = ; j < curBitmap.Width - ; j++)
{
////当前位置是黑色或者是击不中结构元素的这一位置没有选中
if ((tempArray[(i - ) * curBitmap.Width + j - ] == || missStru[] == false) &&
(tempArray[(i - ) * curBitmap.Width + j] == || missStru[] == false) &&
(tempArray[(i - ) * curBitmap.Width + j + ] == || missStru[] == false) &&
(tempArray[i * curBitmap.Width + j - ] == || missStru[] == false) &&
(tempArray[i * curBitmap.Width + j] == || missStru[] == false) &&
(tempArray[i * curBitmap.Width + j + ] == || missStru[] == false) &&
(tempArray[(i + ) * curBitmap.Width + j - ] == || missStru[] == false) &&
(tempArray[(i + ) * curBitmap.Width + j] == || missStru[] == false) &&
(tempArray[(i + ) * curBitmap.Width + j + ] == || missStru[] == false))
{
temp2Array[i * curBitmap.Width + j] = ;
} }
} //两个腐蚀运算结果再进行“与”操作
for (int i = ; i < bytes; i++)
{
if (temp1Array[i] == && temp2Array[i] == )
{
tempArray[i] = ;
}
else
{
tempArray[i] = ;
}
} grayValues = (byte[])tempArray.Clone(); Marshal.Copy(grayValues, , ptr, bytes);
curBitmap.UnlockBits(bmpData);
} Invalidate();
}
}
C#数字图像处理(十四)击中击不中变换 (Hit-miss)的更多相关文章
- OpenCV击中击不中HMTxingt变换最容易理解的解释
OpenCV击中击不中变换是几个形态变换中相对比较拗口.不容易理解的,给初学者理解带来了很多困难,虽然网上也有许多的公开资料,原理和算法基本上介绍比较清晰,但是是要OpenCV进行形态变换大多还是说得 ...
- c#数字图像处理(四)线性点运算
灰度图像的点运算可分为线性点运算和非线性点运算两种.4.1线性点运算定义线性点运算就是输出灰度级与输入灰度级呈线性关系的点运算.在这种情况下,灰度变换函数的形式为: g(x, y)=pf(x,y)+L ...
- c语言数字图像处理(四):灰度变换
灰度变换 灰度变换函数 s = T(r) 其中r为输入图像在(x, y)点处的灰度值,s为输出图像在(x, y)点处的灰度值 灰度变换的作用 上图所示的两幅T(s)函数的图像曲线,第一幅图可以增强 ...
- 数字图像处理 第四章 P157 小错误
问题 我认为P157中部的卷积公式是错的,f(x)h(x-m)应当写为f(m)h(x-m) 解决方法 为了证明,我就用我蹩脚的python实现一下图4.28左列 源代码如下 import numpy ...
- C++数字图像处理(1)-伽马变换
https://blog.csdn.net/huqiang_823/article/details/80767019 1.算法原理 伽马变换(幂律变换)是常用的灰度变换,是一种简单的图像增强算法 ...
- 【数字图像处理】六.MFC空间几何变换之图像平移、镜像、旋转、缩放具体解释
本文主要讲述基于VC++6.0 MFC图像处理的应用知识,主要结合自己大三所学课程<数字图像处理>及课件进行解说,主要通过MFC单文档视图实现显示BMP图片空间几何变换.包含图像平移.图形 ...
- 【数字图像处理】五.MFC图像点运算之灰度线性变化、灰度非线性变化、阈值化和均衡化处理具体解释
本文主要讲述基于VC++6.0 MFC图像处理的应用知识,主要结合自己大三所学课程<数字图像处理>及课件进行解说.主要通过MFC单文档视图实现显示BMP图片点运算处理.包含图像灰度线性变换 ...
- 《C++游戏开发》笔记十四 平滑过渡的战争迷雾(二) 实现:真正的迷雾来了
本系列文章由七十一雾央编写,转载请注明出处. http://blog.csdn.net/u011371356/article/details/9712321 作者:七十一雾央 新浪微博:http:/ ...
- Linux学习总结(十四)—— 查看CPU信息
文章首发于[博客园-陈树义],点击跳转到原文Linux学习总结(十四)-- 查看CPU信息. Linux学习总结(十四)-- 查看CPU信息 商用服务器CPU最常用的是 Intel Xeon 系列,该 ...
随机推荐
- 【转载】VS Code 中的代码自动补全和自动导入包
原文连接:https://maiyang.me/post/2018-09-14-tips-vscode/ VSCode 必须安装以下插件: 首先你必须安装 Golang 插件,然后再给 Go 安装工具 ...
- 几个关于2-sat的题
几个关于2-sat的题 HDU3062 传送门:http://acm.hdu.edu.cn/showproblem.php?pid=3062 题意: 从2n个人去宴会,有 m条关系 i和j不能同时去 ...
- pytorch torch.Stroage();torch.cuda()
转自:https://ptorch.com/news/52.html torch.Storage是单个数据类型的连续的一维数组,每个torch.Tensor都具有相同数据类型的相应存储.他是torch ...
- ant design 的Table组件固定表头时不对齐
现在有一个表格,里面的列数是不固定的(可以重复写入数据),且列数行数都可能很多,就带来一个问题: 必须要固定表头,但是antd 的表格组件设置了固定表格 scroll={{x:1000,y:300}} ...
- Linux 批量安装依赖
1.依赖检测失败,xxx被xxxx需要. 当我安装rpm 的时候,出现依赖检测失败. 我们可以到http://rpmfind.net/linux/rpm2html/search.php 这个网站上去搜 ...
- Docker Swarm Mode简介与核心概念
什么是Docker Swarm Docker Swarm是Docker官方的一种容器编排方案,用于管理跨主机的Docker容器,可以快速对指定服务进行水平扩展.部署.删除 一个Docker Swarm ...
- 【题解】P4585 [FJOI2015]火星商店问题(线段树套Trie树)
[题解]P4585 [FJOI2015]火星商店问题(线段树套Trie树) 语文没学好不要写省选题面!!!! 题目大意: 有\(n\)个集合,每个集合有个任意时刻都可用的初始元素.现在有\(m\)个操 ...
- The Annual Summary Of 2019
Time is flying, it arrives at the end of year again. This is my first year working in PinDuoDuo inc ...
- Ubuntu管理软件源
在Ubuntu环境下,我们经常会使用apt-get(apt)命令下载各种软件,当所需软件在官方软件库中找不到时,我们需要添加第三方的软件源,或者由于位于海外的官方软件源下载速度过于感人时,需要添加国内 ...
- Spark学习笔记(二)—— Local模式
Spark 的运行模式有 Local(也称单节点模式),Standalone(集群模式),Spark on Yarn(运行在Yarn上),Mesos以及K8s等常用模式,本文介绍第一种模式. 1.Lo ...