直方图匹配,又称直方图规定化,即变换原图的直方图为规定的某种形式的直方图,从而使两幅图像具有类似的色调和反差。直方图匹配属于非线性点运算。

直方图规定化的原理:对两个直方图都做均衡化,变成相同的归一化的均匀直方图,以此均匀直方图为媒介,再对参考图像做均衡化的逆运算

     /// <summary>
/// 直方图匹配
/// </summary>
/// <param name="srcBmp">原始图像</param>
/// <param name="matchingBmp">匹配图像</param>
/// <param name="dstBmp">处理后图像</param>
/// <returns>处理成功 true 失败 false</returns>
public static bool HistogramMatching(Bitmap srcBmp, Bitmap matchingBmp, out Bitmap dstBmp)
{
if (srcBmp == null || matchingBmp == null)
{
dstBmp = null;
return false;
}
dstBmp = new Bitmap(srcBmp);
Bitmap tempSrcBmp = new Bitmap(srcBmp);
Bitmap tempMatchingBmp = new Bitmap(matchingBmp);
double[] srcCpR = null;
double[] srcCpG = null;
double[] srcCpB = null;
double[] matchCpB = null;
double[] matchCpG = null;
double[] matchCpR = null;
//分别计算两幅图像的累计概率分布
getCumulativeProbabilityRGB(tempSrcBmp, out srcCpR, out srcCpG, out srcCpB);
getCumulativeProbabilityRGB(tempMatchingBmp, out matchCpR, out matchCpG, out matchCpB); double diffAR = , diffBR = , diffAG = , diffBG = , diffAB = , diffBB = ;
byte kR = , kG = , kB = ;
//逆映射函数
byte[] mapPixelR = new byte[];
byte[] mapPixelG = new byte[];
byte[] mapPixelB = new byte[];
//分别计算RGB三个分量的逆映射函数
//R
for (int i = ; i < ; i++)
{
diffBR = ;
for (int j = kR; j < ; j++)
{
//找到两个累计分布函数中最相似的位置
diffAR = Math.Abs(srcCpR[i] - matchCpR[j]);
if (diffAR - diffBR < 1.0E-08)
{//当两概率之差小于0.000000001时可近似认为相等
diffBR = diffAR;
//记录下此时的灰度级
kR = (byte)j;
}
else
{
kR = (byte)Math.Abs(j - );
break;
}
}
if (kR == )
{
for (int l = i; l < ; l++)
{
mapPixelR[l] = kR;
}
break;
}
mapPixelR[i] = kR;
}
//G
for (int i = ; i < ; i++)
{
diffBG = ;
for (int j = kG; j < ; j++)
{
diffAG = Math.Abs(srcCpG[i] - matchCpG[j]);
if (diffAG - diffBG < 1.0E-08)
{
diffBG = diffAG;
kG = (byte)j;
}
else
{
kG = (byte)Math.Abs(j - );
break;
}
}
if (kG == )
{
for (int l = i; l < ; l++)
{
mapPixelG[l] = kG;
}
break;
}
mapPixelG[i] = kG;
}
//B
for (int i = ; i < ; i++)
{
diffBB = ;
for (int j = kB; j < ; j++)
{
diffAB = Math.Abs(srcCpB[i] - matchCpB[j]);
if (diffAB - diffBB < 1.0E-08)
{
diffBB = diffAB;
kB = (byte)j;
}
else
{
kB = (byte)Math.Abs(j - );
break;
}
}
if (kB == )
{
for (int l = i; l < ; l++)
{
mapPixelB[l] = kB;
}
break;
}
mapPixelB[i] = kB;
}
//映射变换
BitmapData bmpData = dstBmp.LockBits(new Rectangle(, , dstBmp.Width, dstBmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
unsafe
{
byte* ptr = null;
for (int i = ; i < dstBmp.Height; i++)
{
ptr = (byte*)bmpData.Scan0 + i * bmpData.Stride;
for (int j = ; j < dstBmp.Width; j++)
{
ptr[j * + ] = mapPixelR[ptr[j * + ]];
ptr[j * + ] = mapPixelG[ptr[j * + ]];
ptr[j * ] = mapPixelB[ptr[j * ]];
}
}
}
dstBmp.UnlockBits(bmpData);
return true;
} /// <summary>
/// 计算各个图像分量的累计概率分布
/// </summary>
/// <param name="srcBmp">原始图像</param>
/// <param name="cpR">R分量累计概率分布</param>
/// <param name="cpG">G分量累计概率分布</param>
/// <param name="cpB">B分量累计概率分布</param>
private static void getCumulativeProbabilityRGB(Bitmap srcBmp, out double[] cpR, out double[] cpG, out double[] cpB)
{
if (srcBmp == null)
{
cpB = cpG = cpR = null;
return;
}
cpR = new double[];
cpG = new double[];
cpB = new double[];
int[] hR = null;
int[] hG = null;
int[] hB = null;
double[] tempR = new double[];
double[] tempG = new double[];
double[] tempB = new double[];
getHistogramRGB(srcBmp, out hR, out hG, out hB);
int totalPxl = srcBmp.Width * srcBmp.Height;
for (int i = ; i < ; i++)
{
if (i != )
{
tempR[i] = tempR[i - ] + hR[i];
tempG[i] = tempG[i - ] + hG[i];
tempB[i] = tempB[i - ] + hB[i];
}
else
{
tempR[] = hR[];
tempG[] = hG[];
tempB[] = hB[];
}
cpR[i] = (tempR[i] / totalPxl);
cpG[i] = (tempG[i] / totalPxl);
cpB[i] = (tempB[i] / totalPxl);
}
} /// <summary>
/// 获取图像三个分量的直方图数据
/// </summary>
/// <param name="srcBmp">图像</param>
/// <param name="hR">R分量直方图数据</param>
/// <param name="hG">G分量直方图数据</param>
/// <param name="hB">B分量直方图数据</param>
public static void getHistogramRGB(Bitmap srcBmp, out int[] hR, out int[] hG, out int[] hB)
{
if (srcBmp == null)
{
hR = hB = hG = null;
return;
}
hR = new int[];
hB = new int[];
hG = new int[];
BitmapData bmpData = srcBmp.LockBits(new Rectangle(, , srcBmp.Width, srcBmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
unsafe
{
byte* ptr = null;
for (int i = ; i < srcBmp.Height; i++)
{
ptr = (byte*)bmpData.Scan0 + i * bmpData.Stride;
for (int j = ; j < srcBmp.Width; j++)
{
hB[ptr[j * ]]++;
hG[ptr[j * + ]]++;
hR[ptr[j * + ]]++;
}
}
}
srcBmp.UnlockBits(bmpData);
return;
}

c#数字图像处理(七)直方图匹配的更多相关文章

  1. OpenCV-跟我一起学数字图像处理之直方图均衡化

    从这篇博文开始,小生正式从一个毫不相干专业转投数字图像处理.废话不多说了,talk is cheap. show me the code. 直方图均衡化目的 由于一些图像灰度的分布过于集中,这样会导致 ...

  2. Win8 Metro(C#)数字图像处理--3.3图像直方图计算

    原文:Win8 Metro(C#)数字图像处理--3.3图像直方图计算 /// <summary> /// Get the array of histrgram. /// </sum ...

  3. Win8Metro(C#)数字图像处理--2.34直方图规定化

    原文:Win8Metro(C#)数字图像处理--2.34直方图规定化  [函数名称] WriteableBitmap HistogramSpecificateProcess(WriteableBi ...

  4. Win8Metro(C#)数字图像处理--2.30直方图均衡化

    原文:Win8Metro(C#)数字图像处理--2.30直方图均衡化 [函数名称] 直方图均衡化函数HistogramEqualProcess(WriteableBitmap src) [算法说明] ...

  5. FPGA与数字图像处理技术

    数字图像处理方法的重要性源于两个主要应用领域: 改善图像信息以便解释. 为存储.传输和表示而对图像数据进行处理,以便于机器自动理解. 图像处理(image processing): 用计算机对图像进行 ...

  6. 数字图像处理:基于MATLAB的车牌识别项目 标签: 图像处理matlab算法 2017-06-24 09:17 98人阅读 评论(0)

    学过了数字图像处理,就进行一个综合性强的小项目来巩固一下知识吧.前阵子编写调试了一套基于MATLAB的车牌识别的项目的代码.今天又重新改进了一下代码,识别的效果好一点了,也精简了一些代码.这里没有使用 ...

  7. FPGA经典:Verilog传奇与基于FPGA的数字图像处理原理及应用

    一 简述 最近恶补基础知识,借了<<Verilog传奇>>,<基于FPGA的嵌入式图像处理系统设计>和<<基千FPGA的数字图像处理原理及应用>& ...

  8. 数字图像处理的Matlab实现(4)—灰度变换与空间滤波

    第3章 灰度变换与空间滤波(2) 3.3 直方图处理与函数绘图 基于从图像亮度直方图中提取的信息的亮度变换函数,在诸如增强.压缩.分割.描述等方面的图像处理中扮演着基础性的角色.本节的重点在于获取.绘 ...

  9. 数字图像处理实验(总计23个)汇总 标签: 图像处理MATLAB 2017-05-31 10:30 175人阅读 评论(0)

    以下这些实验中的代码全部是我自己编写调试通过的,到此,最后进行一下汇总. 数字图像处理实验(1):PROJECT 02-01, Image Printing Program Based on Half ...

随机推荐

  1. git无密码push

    近来项目中调研,jupyterlab和git的整合内容,git server我使用的gitbucket和bitbucket.(项目要求使用bitbucket,看错一个字母下载了两个镜像) gitbuc ...

  2. 将 using namespace 写在函数体中,以避免命名空间冲突

    将 using namespace xxx 写在函数体中时, 命名空间 xxx 中定义的资源只在该函数体中有效. 测试代码如下图所示(namespace std 只在函数 testFun2 中有效):

  3. Popup a window before the MainWindow

    protected override void OnStartup(StartupEventArgs e) { Window w = new Window(); w.ShowDialog(); bas ...

  4. linux中inode的理解

    一.inode是什么? 理解inode,要从文件储存说起. 文件储存在硬盘上,硬盘的最小存储单位叫做"扇区"(Sector).每个扇区储存512字节(相当于0.5KB). 操作系统 ...

  5. CentOS6.5升级NTP

    二.安装依赖包 yum -y install gcc libcap libcap-devel glibc-devel 三.升级Ntp 1.tar zxf /tmp/ntp-4.2.8p10.tar.g ...

  6. 异常 A component named TableViewForm already exists 解决方法

    用navicate连接mysql,打开数据库表格,出现 A component named TableViewForm already exists  异常信息,如下图: 1.异常原因: 打开的表格数 ...

  7. SpringDataJpa多条件查询代码封装

    package com.pantech.cloud.mlogistics.util; import com.mysql.jdbc.StringUtils; import org.springframe ...

  8. Spring Boot 添加Druid连接池(1.5 版本)

    Druid是一个关系型数据库连接池,是阿里巴巴的一个开源项目,地址:https://github.com/alibaba/druid .Druid不但提供连接池的功能,还提供监控功能,可以实时查看数据 ...

  9. 关于opengl中的矩阵平移,矩阵旋转,推导过程理解 OpenGL计算机图形学的一些必要矩阵运算知识

    原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/12166896.html 为什么引入齐次坐标的变换矩阵可以表示平移呢? - Yu Mao的回答 ...

  10. Vue.js项目在apache服务器部署后,刷新404的问题

    原因是vue-router 使用了路由的 history 模式,这种模式充分利用 history.pushState API 来完成 URL 跳转而无须重新加载页面. const router = n ...