在C#用指针实现快速图像处理
作者:V君 发布于:2014-3-31 11:04 Monday 分类:挖坑经验
先展示一下效果
Cdf 均衡, 算法参考自维基百科 直方图均衡化 条目
平均范围均衡, 自己写的算法
平均Yuv亮度均衡 色彩方面略比RGB均衡好些 转换公式参考了维基百科的 YUV 条目.
(我不会说跌了好几跤,因为忘记clip,转出各种奇怪的颜色 )
最后是代码, 不解释 乂D
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace SS
{
static class ImageProcess
{
//---- utils
private static Bitmap Make32bppRgbCopy(this Image img)
{
var bmp = new Bitmap(img.Width, img.Height
, PixelFormat.Format32bppRgb);
using (var grp = Graphics.FromImage(bmp))
grp.DrawImage(img, new Rectangle(Point.Empty, img.Size));
return bmp;
}
public static BitmapData LockEntire(this Bitmap bmp, ImageLockMode mode, PixelFormat pf)
{
return bmp.LockBits(new Rectangle(Point.Empty, bmp.Size), mode, pf);
}
public static BitmapData LockEntire32Rgb(this Bitmap bmp)
{
return bmp.LockEntire(ImageLockMode.ReadWrite, PixelFormat.Format32bppRgb);
}
public static BitmapData LockEntire32RgbR(this Bitmap bmp)
{
return bmp.LockEntire(ImageLockMode.ReadOnly, PixelFormat.Format32bppRgb);
}
private unsafe static void CalcChannel(byte* orig, byte* dest, int param)
{
if (param == 256)
{
*dest = *orig;
}
else if (param < 256)
{
*dest = (byte)(*orig * (param / 255f));
}
else if (param > 256)
{
var ava = (255 - *orig);
var pva = (param - 256);
var ppe = (pva / 255f);
var adv = ava * ppe;
*dest = (byte)(adv + *orig);
}
}
private static byte Clip(float value)
{
if (value < byte.MinValue) return byte.MinValue;
if (value > byte.MaxValue) return byte.MaxValue;
return (byte)Math.Round(value);
}
//---- base cls
private abstract unsafe class ImageProcessor
{
protected delegate void ProcessPixel(int px, int py, byte* r, byte* g, byte* b);
protected void ProcessImageInternal(BitmapData lck, ProcessPixel ProcessPixel)
{
var ptr0 = (byte*)lck.Scan0.ToPointer();
byte* ptrLine, ptrPix, r, g, b;
for (int i = 0; i < lck.Height; ++i)
{
ptrLine = ptr0 + (i * lck.Stride);
for (int j = 0; j < lck.Width; ++j)
{
ptrPix = ptrLine + (j * 4);
b = ptrPix + 0;
g = ptrPix + 1;
r = ptrPix + 2;
ProcessPixel(j, i, r, g, b);
}
}
}
public abstract Image ProcessImage(Image img);
}
private abstract unsafe class YuvImageProcessor : ImageProcessor
{
protected float y, u, v;
protected void ConvYuv(byte* r, byte* g, byte* b)
{
//rgb > yuv
y = (0.299f * *r + 0.587f * *g + 0.114f * *b);
u = 0.436f * (*b - y) / (1 - 0.144f) + 128;
v = 0.615f * (*r - y) / (1 - 0.299f) + 128;
}
protected void ConvRgb(byte* r, byte* g, byte* b)
{
//yuv > rgb
*r = Clip(y + 1.13983f * (v - 128));
*g = Clip(y - 0.39465f * (u - 128) - 0.58060f * (v - 128));
*b = Clip(y + 2.03211f * (u - 128));
}
}
//---- impl cls
private unsafe class HVMImageProcessor : ImageProcessor
{
float[,] arrHor, arrVer;
private bool? hvm;
public HVMImageProcessor(bool? hvm)
{
this.hvm = hvm;
}
public override Image ProcessImage(Image img)
{
var bmp = img.Make32bppRgbCopy();
var lck = bmp.LockEntire32Rgb();
arrHor = new float[lck.Width, 3];
arrVer = new float[lck.Height, 3];
ProcessImageInternal(lck, ComputeHV);
ProcVal(arrHor, lck.Height);
ProcVal(arrVer, lck.Width);
switch (hvm)
{
case true:
ProcessImageInternal(lck, GenerateH);
break;
case false:
ProcessImageInternal(lck, GenerateV);
break;
case null:
ProcessImageInternal(lck, GenerateM);
break;
default:
throw new ArgumentException("hvm is not a Nullable<bool>?");
}
bmp.UnlockBits(lck);
return bmp;
}
private static void ProcVal(float[,] arr, int div)
{
var len1 = arr.GetLength(0);
var len2 = arr.GetLength(1);
for (int i = 0; i < len1; i++)
{
for (int j = 0; j < len2; j++)
{
arr[i, j] /= div;
}
}
}
private void ComputeHV(int x, int y, byte* ptrR, byte* ptrG, byte* ptrB)
{
arrHor[x, 0] += *ptrB;
arrHor[x, 1] += *ptrG;
arrHor[x, 2] += *ptrR;
arrVer[y, 0] += *ptrB;
arrVer[y, 1] += *ptrG;
arrVer[y, 2] += *ptrR;
}
private void GenerateH(int x, int y, byte* ptrR, byte* ptrG, byte* ptrB)
{
*ptrB = (byte)arrHor[x, 0];
*ptrG = (byte)arrHor[x, 1];
*ptrR = (byte)arrHor[x, 2];
}
private void GenerateV(int x, int y, byte* ptrR, byte* ptrG, byte* ptrB)
{
*ptrB = (byte)arrVer[y, 0];
*ptrG = (byte)arrVer[y, 1];
*ptrR = (byte)arrVer[y, 2];
}
private void GenerateM(int x, int y, byte* ptrR, byte* ptrG, byte* ptrB)
{
*ptrB = (byte)((arrHor[x, 0] + arrVer[y, 0]) / 2.0);
*ptrG = (byte)((arrHor[x, 1] + arrVer[y, 1]) / 2.0);
*ptrR = (byte)((arrHor[x, 2] + arrVer[y, 2]) / 2.0);
}
}
private unsafe class ChannelsImageProcessor : ImageProcessor
{
private int cr;
private int cg;
private int cb;
public ChannelsImageProcessor(int cr, int cg, int cb)
{
this.cr = cr;
this.cg = cg;
this.cb = cb;
}
public override Image ProcessImage(Image img)
{
var bmp = img.Make32bppRgbCopy();
var lck = bmp.LockEntire32Rgb();
ProcessImageInternal(lck, ProcessChannel);
bmp.UnlockBits(lck);
return bmp;
}
private void ProcessChannel(
int x, int y, byte* ptrR, byte* ptrG, byte* ptrB)
{
CalcChannel(ptrB, ptrB, cb);
CalcChannel(ptrG, ptrG, cg);
CalcChannel(ptrR, ptrR, cr);
}
}
private unsafe class EqPerImageProcessor : ImageProcessor
{
byte min_r = byte.MaxValue;
byte min_g = byte.MaxValue;
byte min_b = byte.MaxValue;
byte max_r = byte.MinValue;
byte max_g = byte.MinValue;
byte max_b = byte.MinValue;
int rng_r;
int rng_g;
int rng_b;
public override Image ProcessImage(Image img)
{
var bmp = img.Make32bppRgbCopy();
var lck = bmp.LockEntire32Rgb();
ProcessImageInternal(lck, CalcRng);
rng_r = max_r - min_r;
rng_g = max_g - min_g;
rng_b = max_b - min_b;
ProcessImageInternal(lck, GenerateResult);
bmp.UnlockBits(lck);
return bmp;
}
private void CalcRng(int x, int y, byte* r, byte* g, byte* b)
{
if (min_r > *r) min_r = *r;
if (min_g > *g) min_g = *g;
if (min_b > *b) min_b = *b;
if (max_r < *r) max_r = *r;
if (max_g < *g) max_g = *g;
if (max_b < *b) max_b = *b;
}
private void GenerateResult(int x, int y, byte* r, byte* g, byte* b)
{
*b = (byte)(((float)*b - min_b) / rng_b * 255);
*g = (byte)(((float)*g - min_g) / rng_g * 255);
*r = (byte)(((float)*r - min_r) / rng_r * 255);
}
}
private unsafe class EqPerYuvImageProcessor : YuvImageProcessor
{
float min_y = float.MaxValue;
float min_u = float.MaxValue;
float min_v = float.MaxValue;
float max_y = float.MinValue;
float max_u = float.MinValue;
float max_v = float.MinValue;
float rng_y;
float rng_u;
float rng_v;
public override Image ProcessImage(Image img)
{
var bmp = img.Make32bppRgbCopy();
var lck = bmp.LockEntire32Rgb();
ProcessImageInternal(lck, CalcRng);
rng_y = max_y - min_y;
rng_u = max_u - min_u;
rng_v = max_v - min_v;
ProcessImageInternal(lck, GenerateResult);
bmp.UnlockBits(lck);
return bmp;
}
private void CalcRng(int px, int py, byte* r, byte* g, byte* b)
{
ConvYuv(r, g, b);
if (min_y > y) min_y = y;
if (min_u > u) min_u = u;
if (min_v > v) min_v = v;
if (max_y < y) max_y = y;
if (max_u < u) max_u = u;
if (max_v < v) max_v = v;
}
private void GenerateResult(int px, int py, byte* r, byte* g, byte* b)
{
ConvYuv(r, g, b);
//calc perccent
y = (y - min_y) / rng_y * 255;
//u = (u - min_u) / rng_u * 255;
//v = (v - min_v) / rng_v * 255;
ConvRgb(r, g, b);
}
}
private unsafe class EqHisImageProcssor : ImageProcessor
{
int[] cdf_r = new int[256];
int[] cdf_g = new int[256];
int[] cdf_b = new int[256];
int cdf_min_r = int.MaxValue;
int cdf_min_g = int.MaxValue;
int cdf_min_b = int.MaxValue;
int totalPixel;
public override Image ProcessImage(Image img)
{
var bmp = img.Make32bppRgbCopy();
var lck = bmp.LockEntire32Rgb();
totalPixel = lck.Width * lck.Height;
ProcessImageInternal(lck, CalcCdf);
ProcCdf();
ProcessImageInternal(lck, GenerateResult);
bmp.UnlockBits(lck);
return bmp;
}
private void ProcCdf()
{
for (int i = 0; i < 256; i++)
{
if (cdf_r[i] != 0)
{
for (int s = i - 1; s >= 0; s--)
{
if (cdf_r[s] == 0)
continue;
cdf_r[i] += cdf_r[s];
break;
}
if (cdf_min_r > cdf_r[i])
cdf_min_r = cdf_r[i];
}
if (cdf_g[i] != 0)
{
for (int s = i - 1; s >= 0; s--)
{
if (cdf_g[s] == 0)
continue;
cdf_g[i] += cdf_g[s];
break;
}
if (cdf_min_g > cdf_g[i])
cdf_min_g = cdf_g[i];
}
if (cdf_b[i] != 0)
{
for (int s = i - 1; s >= 0; s--)
{
if (cdf_b[s] == 0)
continue;
cdf_b[i] += cdf_b[s];
break;
}
if (cdf_min_b > cdf_b[i])
cdf_min_b = cdf_b[i];
}
}
}
private void CalcCdf(int px, int py, byte* r, byte* g, byte* b)
{
cdf_r[*r]++;
cdf_g[*g]++;
cdf_b[*b]++;
}
private void GenerateResult(int px, int py, byte* r, byte* g, byte* b)
{
*r = (byte)(((cdf_r[*r] - cdf_min_r) / (totalPixel - 1.0)) * 255);
*g = (byte)(((cdf_g[*g] - cdf_min_g) / (totalPixel - 1.0)) * 255);
*b = (byte)(((cdf_b[*b] - cdf_min_b) / (totalPixel - 1.0)) * 255);
}
}
private unsafe class EqHisYuvImageProcessor : YuvImageProcessor
{
byte* ptrLine;
byte* ptrPix;
int[] cdf_y = new int[256];
int[] cdf_u = new int[256];
int[] cdf_v = new int[256];
int cdf_min_y = int.MaxValue;
int cdf_min_u = int.MaxValue;
int cdf_min_v = int.MaxValue;
int totalPixel;
public override Image ProcessImage(Image img)
{
var bmp = img.Make32bppRgbCopy();
var lck = bmp.LockEntire32Rgb();
totalPixel = lck.Width * lck.Height;
ProcessImageInternal(lck, CalcCdf);
ProccCdf();
ProcessImageInternal(lck, GenerateResult);
bmp.UnlockBits(lck);
return bmp;
}
private void CalcCdf(int px, int py, byte* r, byte* g, byte* b)
{
ConvYuv(r, g, b);
cdf_y[Clip(y)]++;
cdf_u[Clip(u)]++;
cdf_v[Clip(v)]++;
}
private void ProccCdf()
{
for (int i = 0; i < 256; i++)
{
if (cdf_y[i] != 0)
{
for (int s = i - 1; s >= 0; s--)
{
if (cdf_y[s] == 0)
continue;
cdf_y[i] += cdf_y[s];
break;
}
if (cdf_min_y > cdf_y[i])
cdf_min_y = cdf_y[i];
}
if (cdf_u[i] != 0)
{
for (int s = i - 1; s >= 0; s--)
{
if (cdf_u[s] == 0)
continue;
cdf_u[i] += cdf_u[s];
break;
}
if (cdf_min_u > cdf_u[i])
cdf_min_u = cdf_u[i];
}
if (cdf_v[i] != 0)
{
for (int s = i - 1; s >= 0; s--)
{
if (cdf_v[s] == 0)
continue;
cdf_v[i] += cdf_v[s];
break;
}
if (cdf_min_v > cdf_v[i])
cdf_min_v = cdf_v[i];
}
}
}
private void GenerateResult(int px, int py, byte* r, byte* g, byte* b)
{
ConvYuv(r, g, b);
//cdf - y
y = (((cdf_y[(byte)y] - cdf_min_y) / (totalPixel - 1.0f)) * 255);
//uf = (((cdf_u[(byte)uf] - cdf_min_u) / (totalPixel - 1.0f)) * 255);
//vf = (((cdf_v[(byte)vf] - cdf_min_v) / (totalPixel - 1.0f)) * 255);
ConvRgb(r, g, b);
}
}
private unsafe class BmImageProccessor : ImageProcessor
{
private bool andOr;
private int xr;
private int xg;
private int xb;
public BmImageProccessor(bool andOr, int xr, int xg, int xb)
{
this.andOr = andOr;
this.xr = xr;
this.xg = xg;
this.xb = xb;
}
public override Image ProcessImage(Image img)
{
var source = img.Make32bppRgbCopy();
var result = new Bitmap(source.Width, source.Height, PixelFormat.Format8bppIndexed);
//init as bm
var pat = result.Palette;
pat.Entries[0] = Color.Black;
pat.Entries[1] = Color.White;
result.Palette = pat;
var datSource = source.LockEntire32RgbR();
var datResult = result.LockEntire(
ImageLockMode.WriteOnly
, PixelFormat.Format8bppIndexed
);
byte* scanSource = (byte*)datSource.Scan0.ToPointer();
byte* scanResult = (byte*)datResult.Scan0.ToPointer();
byte* prtLineSource, prtLineResult, ptrPixSource, ptrPixResult;
for (int i = 0; i < datSource.Height; ++i)
{
prtLineSource = scanSource + (i * datSource.Stride);
prtLineResult = scanResult + (i * datResult.Stride);
for (int j = 0; j < datSource.Width; ++j)
{
ptrPixSource = prtLineSource + (j * 4);
ptrPixResult = prtLineResult + (j);
bool flag;
if (andOr)
flag = ptrPixSource[0] > xb
&& ptrPixSource[1] > xg
&& ptrPixSource[2] > xr;
else
flag = ptrPixSource[0] > xb
|| ptrPixSource[1] > xg
|| ptrPixSource[2] > xr;
if (flag)
*ptrPixResult = 1;
else
*ptrPixResult = 0;
}
}
result.UnlockBits(datResult);
source.UnlockBits(datSource);
source.Dispose();
return result;
}
}
//---- pub func
public static Image ProcBM(this Image img, bool andOr, int xrgb)
{
return img.ProcBM(andOr, xrgb, xrgb, xrgb);
}
public static Image ProcBM(this Image img, bool andOr, int xr, int xg, int xb)
{
return new BmImageProccessor(andOr, xr, xg, xb).ProcessImage(img);
}
public static Image ProcChannels(this Image img, int crgb)
{
return img.ProcChannels(crgb, crgb, crgb);
}
public static Image ProcChannels(this Image img, int cr, int cg, int cb)
{
return new ChannelsImageProcessor(cr, cg, cb).ProcessImage(img);
}
public static Image ProcEqPer(this Image img)
{
return new EqPerImageProcessor().ProcessImage(img);
}
public static Image ProcEqHis(this Image img)
{
return new EqHisImageProcssor().ProcessImage(img);
}
public static Image ProcEqPerYuv(this Image img)
{
return new EqPerYuvImageProcessor().ProcessImage(img);
}
public static Image ProcEqHisYuv(this Image img)
{
return new EqHisYuvImageProcessor().ProcessImage(img);
}
public static Image ProcHVM(this Image img, bool? hvm)
{
return new HVMImageProcessor(hvm).ProcessImage(img);
}
}
}
这个月总算赶上消灭0篇博文! 乂D
~
blogger
Google Web Translator
热门日志
随机日志
最新日志
最新评论
- V君
@Quartz:(出现)... - Quartz
怎么不见人了呢... - V君
@Soar:DHCP 协议相... - V君
@Soar:当然是非... - Soar
@V君:谢谢 有空... - Soar
搞一个 1230v3+B85... - V君
@Soar:另外,也可... - V君
@Soar:iscsi服务端... - Soar
难怪这么卡,尤其... - Soar
clone了源码,提示...
分类
存档
- 2024年5月(1)
- 2023年7月(1)
- 2023年5月(1)
- 2022年11月(1)
- 2022年10月(1)
- 2022年9月(1)
- 2022年8月(1)
- 2022年7月(1)
- 2022年6月(1)
- 2022年5月(2)
- 2022年4月(1)
- 2022年3月(1)
- 2022年2月(1)
- 2022年1月(1)
- 2021年12月(1)
- 2021年11月(1)
- 2021年10月(1)
- 2021年9月(1)
- 2021年8月(1)
- 2021年7月(1)
- 2021年6月(1)
- 2021年5月(1)
- 2021年4月(1)
- 2021年3月(1)
- 2021年2月(1)
- 2021年1月(1)
- 2020年12月(1)
- 2020年11月(1)
- 2020年10月(2)
- 2020年9月(1)
- 2020年8月(1)
- 2020年7月(1)
- 2020年6月(1)
- 2020年5月(1)
- 2020年4月(2)
- 2020年3月(3)
- 2020年2月(1)
- 2020年1月(1)
- 2019年12月(1)
- 2019年11月(1)
- 2019年10月(1)
- 2019年9月(1)
- 2019年8月(2)
- 2019年7月(1)
- 2019年6月(1)
- 2019年5月(1)
- 2019年4月(1)
- 2019年3月(1)
- 2019年2月(1)
- 2019年1月(2)
- 2018年12月(2)
- 2018年11月(1)
- 2018年10月(3)
- 2018年9月(4)
- 2018年8月(6)
- 2018年7月(4)
- 2018年6月(1)
- 2018年5月(2)
- 2018年4月(2)
- 2018年3月(3)
- 2018年2月(1)
- 2018年1月(1)
- 2017年12月(1)
- 2017年10月(2)
- 2017年9月(1)
- 2017年8月(2)
- 2017年7月(1)
- 2017年6月(5)
- 2017年5月(2)
- 2017年4月(2)
- 2017年3月(3)
- 2017年2月(2)
- 2017年1月(2)
- 2016年12月(3)
- 2016年11月(2)
- 2016年10月(3)
- 2016年9月(4)
- 2016年8月(2)
- 2016年7月(4)
- 2016年6月(3)
- 2016年5月(1)
- 2016年4月(4)
- 2016年3月(3)
- 2016年2月(1)
- 2016年1月(5)
- 2015年12月(4)
- 2015年11月(5)
- 2015年10月(1)
- 2015年9月(6)
- 2015年8月(4)
- 2015年7月(1)
- 2015年6月(6)
- 2015年5月(3)
- 2015年4月(3)
- 2015年3月(2)
- 2015年2月(1)
- 2015年1月(3)
- 2014年12月(1)
- 2014年11月(1)
- 2014年10月(1)
- 2014年9月(3)
- 2014年8月(1)
- 2014年7月(1)
- 2014年6月(1)
- 2014年5月(3)
- 2014年4月(1)
- 2014年3月(1)
- 2014年2月(2)
- 2014年1月(1)
- 2013年12月(2)
- 2013年11月(2)
- 2013年10月(1)
- 2013年9月(3)
- 2013年8月(14)
- 2013年7月(7)
- 2013年4月(1)
- 2013年3月(4)
- 2013年2月(6)
- 2013年1月(6)
- 2012年12月(8)
- 2012年11月(6)
发表评论: