EmguCV学习(二)
来源:互联网 发布:围巾材质分类 知乎 编辑:程序博客网 时间:2024/06/05 06:55
(1)图像锐化处理
//此部分代码功能是锐化图像,本质上是 扫描图像并访问相邻像素//sharpened_pixel=5*current-left-right-up-downbyte saturateCast(double inValue){ if (inValue < 0) return 0; else if (inValue > 255) return 255; else return (byte)inValue;}bool sharpen(Mat inImg,Mat outImg){ int nchannel = inImg.NumberOfChannels; int nrows = inImg.Rows; int ncols = inImg.Cols; if(nchannel==1) { var tempImg=inImg.ToImage<Gray,byte>(); var tempImg2 = tempImg.Clone(); for(int i=1;i<nrows-1;++i) { for(int j=1;j<ncols-1;++j) { tempImg2.Data[i, j, 0] = saturateCast(5 * tempImg.Data[i, j, 0] - tempImg.Data[i - 1, j, 0] - tempImg.Data[i, j - 1, 0] - tempImg2.Data[i + 1, j, 0] - tempImg.Data[i, j + 1, 0]); } } for(int i=0;i<nrows;++i) { tempImg2.Data[i, 0, 0] = 0; tempImg2.Data[i, ncols - 1, 0] = 0; } for(int j=0;j<ncols;++j) { tempImg2.Data[0, j, 0] = 0; tempImg2.Data[nrows - 1, j, 0] = 0; } tempImg2.Mat.CopyTo(outImg); } else if(nchannel==3) { var tempImg = inImg.ToImage<Bgr, byte>(); var tempImg2 = tempImg.Clone(); for(int i=1;i<nrows-1;++i) { for(int j=1;j<ncols-1;++j) { for(int channel=0;channel<3;channel++) { tempImg2.Data[i, j, channel] = saturateCast(5 * tempImg.Data[i, j, channel] - tempImg.Data[i - 1, j, channel] - tempImg.Data[i, j - 1, channel] - tempImg.Data[i + 1, j, channel] - tempImg.Data[i, j + 1, channel]); } } } for(int i=0;i<nrows;++i) { for(int channel=0;channel<3;channel++) { tempImg2.Data[i, 0, channel] = 0; tempImg2.Data[i, ncols - 1, channel] = 0; } } for(int j=0;j<ncols;++j) { for(int channel=0;channel<3;channel++) { tempImg2.Data[0, j, channel] = 0; tempImg2.Data[nrows - 1, j, channel] = 0; } } tempImg2.Mat.CopyTo(outImg); }else { return false; } return true;}private void button27_Click(object sender, EventArgs e){ Mat inImage = new Mat(); Mat outImage = new Mat(); if (chapter1OFD.ShowDialog() == DialogResult.OK) inImage = CvInvoke.Imread(chapter1OFD.FileName, LoadImageType.AnyColor | LoadImageType.AnyDepth); if (inImage.IsEmpty) return; if (!sharpen(inImage, outImage)) return; if (outImage.IsEmpty) return; imageBox7.Image = outImage;}private void button28_Click(object sender, EventArgs e){ if (chapter2Img.IsEmpty) return; Image<Gray, float> kernelI = new Image<Gray, float>(3, 3, new Gray(0)); kernelI.Data[1, 1, 0] = (float)5.0; kernelI.Data[0, 1, 0] = (float)-1.0; kernelI.Data[1, 0, 0] = (float)-1.0; kernelI.Data[2, 1, 0] = (float)-1.0; kernelI.Data[1, 2, 0] = (float)-1.0; if(chapter2Img.NumberOfChannels==3) { var tempImg = chapter2Img.ToImage<Bgr, byte>(); Image<Gray,byte>[] results = tempImg.Split(); CvInvoke.Filter2D(results[0].Mat, results[0].Mat, kernelI.Mat, new Point(-1, -1)); CvInvoke.Filter2D(results[1].Mat, results[1].Mat, kernelI.Mat, new Point(-1, -1)); CvInvoke.Filter2D(results[2].Mat, results[2].Mat, kernelI.Mat, new Point(-1, -1)); for(int i=0;i<tempImg.Rows;i++) for(int j=0;j<tempImg.Cols;j++) { tempImg.Data[i, j, 0] = results[0].Data[i, j, 0]; tempImg.Data[i, j, 1] = results[1].Data[i, j, 0]; tempImg.Data[i, j, 2] = results[2].Data[i, j, 0]; } imageBox7.Image = tempImg; } else if(chapter2Img.NumberOfChannels==1) { var tempImg = chapter2Img.ToImage<Gray, byte>(); CvInvoke.Filter2D(tempImg.Mat, tempImg.Mat, kernelI.Mat, new Point(-1, -1)); imageBox7.Image = tempImg; }}
以上两部分按钮,一个用的是自定义的函数进行锐化处理,一个用到了filter2d函数
(2)检测图片中的颜色(本例中为浅蓝色),并显示检测结果,监测结果为二值图像,白色表示所检测的颜色部分,黑色表示非所检测颜色部分
Mat chapter3Img = new Mat();private void button29_Click(object sender, EventArgs e){ if(chapter1OFD.ShowDialog()==DialogResult.OK) { chapter3Img = CvInvoke.Imread(chapter1OFD.FileName, LoadImageType.AnyColor | LoadImageType.AnyDepth); if (chapter3Img.IsEmpty) return; } imageBox11.Image = chapter3Img;}private void button30_Click(object sender, EventArgs e){ if (chapter3Img.IsEmpty) return; ColorDetector cd = new ColorDetector(); cd.setTargetColor(230, 190, 130); var result = cd.process(chapter3Img); CvInvoke.NamedWindow("result", NamedWindowType.Normal); CvInvoke.Imshow("result", result);} }public class ColorDetector{ private int maxDist; private MCvScalar targetColor; private Mat result=new Mat(); private void setTarget(int b,int g,int r){ targetColor.V0 = b; targetColor.V1 = g; targetColor.V2 = r;}public void setTargetColor(byte blue,byte green,byte red){ setTarget(blue, green, red);}public void setTargetColor(Color c){ setTarget(c.B, c.G, c.R);}int getColorDistance(Color c1,Color c2){ return (int)Math.Sqrt(Math.Pow((c1.B - c2.B), 2) + Math.Pow((c1.G - c2.G), 2) + Math.Pow((c1.R - c2.R), 2));}int getDistanceToTargetColor(Color c){ Color tempC; tempC = Color.FromArgb((int)targetColor.V2, (int)targetColor.V1, (int)targetColor.V0); var ds=getColorDistance(c, tempC); ////以下是采用opencv的norm函数进行计算,仅仅为了说明一下,故将其注释掉 //Mat temp = new Mat(3, 1, DepthType.Cv64F, 1); //var tempImg = temp.ToImage<Gray,float>(); //tempImg.Data[0, 0, 0] = c.R - tempC.R; //tempImg.Data[1, 0, 0] = c.G - tempC.G; //tempImg.Data[2, 0, 0] = c.B - tempC.B; //var opencvDs = CvInvoke.Norm(tempImg); ////over return (int)ds;}public ColorDetector(){ maxDist = 100; setTarget(0, 0, 0);}void setColorDistanceThreshold(int distance){ if (distance < 0) distance = 0; maxDist = distance;}int getColorDistanceThreshold(){ return maxDist;}public Mat process(Mat inImg){ result.Create(inImg.Rows, inImg.Cols, DepthType.Cv8U, 1); var tempImg = result.ToImage<Gray, byte>(); var tempImg2 = inImg.ToImage<Bgr, byte>(); for(int i=0;i<tempImg2.Rows;i++) for(int j=0;j<tempImg2.Cols;j++) { if(getDistanceToTargetColor(Color.FromArgb(tempImg2.Data[i,j,2], tempImg2.Data[i, j, 1], tempImg2.Data[i, j, 0]))<maxDist) { tempImg.Data[i, j, 0] = 255; } else { tempImg.Data[i, j, 0] = 0; } } tempImg.Mat.CopyTo(result); return result;}
(3)HSV彩色空间,以及基于色调和饱和度的皮肤检测
private void button31_Click(object sender, EventArgs e)//HSV分离{ if (chapter3Img.IsEmpty) return; var tempImg = new Mat(); CvInvoke.CvtColor(chapter3Img, tempImg, ColorConversion.Bgr2Hsv); if (tempImg.IsEmpty) return; var imgs = tempImg.Split(); imageBox12.Image = imgs[2]; imageBox14.Image = imgs[1]; imageBox13.Image = imgs[0];} private void button32_Click(object sender, EventArgs e){ if (chapter3Img.IsEmpty) return; var tempImg = new Mat(); CvInvoke.CvtColor(chapter3Img, tempImg, ColorConversion.Bgr2Hsv); if (tempImg.IsEmpty) return; //var imgs = tempImg.Split(); //imgs[2].SetTo(new MCvScalar(255)); var img = tempImg.ToImage<Hsv, byte>(); for(int i=0;i<img.Rows;i++) for(int j=0;j<img.Cols;j++) { img.Data[i, j, 2] = 255;//统一亮度 } CvInvoke.CvtColor(img.Mat, tempImg, ColorConversion.Hsv2Bgr); imageBox15.Image = tempImg;}//基于HSV彩色空间的皮肤识别void detectHScolor(Mat inImg,double minHue,double maxHue,double minSat,double maxSat,out Mat mask){ Mat HSVImg=new Mat(); CvInvoke.CvtColor(inImg, HSVImg, ColorConversion.Bgr2Hsv); var hsvImgs = HSVImg.ToImage<Hsv, byte>().Split(); //色调掩码 Mat mask1 = new Mat();//小于maxHue CvInvoke.Threshold(hsvImgs[0], mask1, maxHue, 255,ThresholdType.BinaryInv); Mat mask2 = new Mat();//大于minHue CvInvoke.Threshold(hsvImgs[0], mask2, minHue, 255, ThresholdType.Binary); Mat hueMask = new Mat();//色调掩码 if (minHue < maxHue) CvInvoke.BitwiseAnd(mask1, mask2, hueMask); else CvInvoke.BitwiseOr(mask1, mask2, hueMask); //饱和度掩码 CvInvoke.Threshold(hsvImgs[1], mask1, maxSat, 255, ThresholdType.BinaryInv); CvInvoke.Threshold(hsvImgs[1], mask2, minSat, 255, ThresholdType.Binary); Mat satMask = new Mat();//饱和度掩码 CvInvoke.BitwiseAnd(mask1, mask2, satMask); mask = new Mat(); CvInvoke.BitwiseAnd(hueMask, satMask, mask); CvInvoke.NamedWindow("hue", NamedWindowType.Normal); CvInvoke.NamedWindow("sat", NamedWindowType.Normal); CvInvoke.Imshow("hue", hueMask); CvInvoke.Imshow("sat", satMask);}private void button33_Click(object sender, EventArgs e){ if (chapter3Img.IsEmpty) return; Mat resultImg = new Mat(); detectHScolor(chapter3Img, 160, 10, 25, 166, out resultImg); Mat detectedImg = chapter3Img.Clone(); detectedImg.SetTo(new MCvScalar(0, 0, 0)); chapter3Img.CopyTo(detectedImg, resultImg); imageBox16.Image = detectedImg;}
(4)直方图显示(灰度图像)
不得不吐槽下,我是准备用
public static void CalcHist(IInputArray images, int[] channels, IInputArray mask, IOutputArray hist, int[] histSize, float[] ranges, bool accumulate);
这个函数来进行计算的,但不知道为何,运行的时候总是会提示错误,捣鼓半天也查不到解决方案。然后,发现了Emgucv3的一个叫做DenseHistogram的类,该类主要是用来生成1D的直方图数据,颇为好用,故此部分用该类进行相关计算。在进行显示时,我用到了两种方法:使用HistogramViewer和使用HistogramBox控件。以下为代码:
Mat chapter4Img = new Mat();private void button34_Click(object sender, EventArgs e){ if (chapter1OFD.ShowDialog() == DialogResult.OK) chapter4Img = CvInvoke.Imread(chapter1OFD.FileName, LoadImageType.AnyColor | LoadImageType.AnyDepth); if (chapter4Img.IsEmpty) return; imageBox17.Image = chapter4Img;}//以下是直方图计算类(灰度图像),内部使用DenseHistogram类class HisttoGram1D{ private int[] channels=new int[1];//使用的通道index private int[] histSize= new int[1];//bin数量 private RangeF[] ranges=new RangeF[1];//像素值范围 private Mat mask=new Mat();//掩码 private Mat hist=new Mat();//得到的直方图数据 public HisttoGram1D() { channels[0] = 0; histSize[0] = 256; ranges[0] = new RangeF(0.0f, 255.1f); } public DenseHistogram getDenseHistogram(Mat inImg) { if (inImg.IsEmpty) { return null; } DenseHistogram dh = new DenseHistogram(histSize, ranges); var imgs = inImg.ToImage<Gray, byte>().Split(); dh.Calculate(imgs, false, null);//计算直方图信息 return dh; }}//直方图类定义overprivate void button35_Click(object sender, EventArgs e)//单通道图像{ Mat tempImg = new Mat(); HisttoGram1D ht1D = new HisttoGram1D(); if (chapter4Img.NumberOfChannels != 1) { CvInvoke.CvtColor(chapter4Img, tempImg, ColorConversion.Bgr2Gray);//彩色转灰度 } else { tempImg = chapter4Img.Clone(); } if (tempImg.IsEmpty) return; imageBox17.Image = tempImg; //以下采用HistogramViewer类直接显示图像直方图 HistogramViewer hv = new HistogramViewer(); hv.Text = "单通道直方图"; hv.ShowInTaskbar = true; hv.HistogramCtrl.GenerateHistograms(tempImg, 256); hv.WindowState = FormWindowState.Normal; hv.Show(); hv.Refresh(); //还有一种方式,直接使用HistogramViewer的静态函数,HistogramViewer.show(tempImg,256);也可以 //以下使用HistogramBox控件进行直方图显示,需要配合DenseHistogram类 var dhData = ht1D.getDenseHistogram(tempImg);//获取DenseHistogram对象 //值得注意的是,此时dhData,也就是DenseHistogram类,虽然是继承的Mat类,但里面存储的已经是直方图信息 histogramBox2.ClearHistogram(); histogramBox2.AddHistogram("HistogramBox控件显示单通道直方图", Color.FromArgb(255, 0, 0), dhData, 256, new float[] { 0.0f, 255.0f }); histogramBox2.Refresh(); int[] testt = new int[256]; var ttt = tempImg.ToImage<Gray, byte>(); for(int i=0;i<tempImg.Rows;i++) for(int j=0;j<tempImg.Cols;j++) { testt[ttt.Data[i, j, 0]]++; } int ii = 0; for(int i=0;i<testt.Length;i++) { ii += testt[i]; } double iii = 0.0; for(int i=0;i<dhData.GetBinValues().Length;i++) { iii += dhData.GetBinValues()[i]; } int iiii = 0;}
ranges[0] = new RangeF(0.0f, 255.1f);
如果将RangeF的范围设为0-255,最后得到的直方图会缺少像素值为255点的统计信息。原因我猜是rangeF的范围取值是[ min,max )方式吧。
这个问题把我困了n久。。。囧
接下来的小节我将重写一个直方图类,借助DenseHistogram,实现探测图像的通道(暂定为单通道和RGB彩色图像),并显示直方图。
(5)这一部分,可以读取无论是RGB三通道图像还是Gray单通道图像,并生成直方图的Mat数据并显示。
另外,还完成了点击“计算RGB直方图”这一按钮功能。
//定义函数,输入Mat图像,输出DenseHistogram对象DenseHistogram[] getDenseHistogramDataOfImage(Mat inImg)//这里的inImg深度暂定为byte{ DenseHistogram[] dh = new DenseHistogram[3] { new DenseHistogram(256, new RangeF(0f, 255.1f)), new DenseHistogram(256, new RangeF(0f, 255.1f)), new DenseHistogram(256, new RangeF(0f, 255.1f)) }; if (inImg.NumberOfChannels==3) { dh[0].Calculate(new Image<Gray, byte>[] { inImg.ToImage<Bgr, byte>()[0] }, false, null); dh[1].Calculate(new Image<Gray, byte>[] { inImg.ToImage<Bgr, byte>()[1] }, false, null); dh[2].Calculate(new Image<Gray, byte>[] { inImg.ToImage<Bgr, byte>()[2] }, false, null); } else { dh[0].Calculate(new Image<Gray, byte>[] { inImg.ToImage<Gray, byte>()[0] }, false, null); dh[1] = null; dh[2] = null; } return dh;}private void button36_Click(object sender, EventArgs e){ if (chapter4Img.IsEmpty) return; var dhData = getDenseHistogramDataOfImage(chapter4Img); histogramBox2.ClearHistogram(); if(chapter4Img.NumberOfChannels==3) { histogramBox2.AddHistogram("Blue直方图", Color.FromArgb(0, 0, 255), dhData[0], 256, new float[] { 0.0f, 255.0f }); histogramBox2.AddHistogram("Green直方图", Color.FromArgb(0, 255, 0), dhData[1], 256, new float[] { 0.0f, 255.0f }); histogramBox2.AddHistogram("Red直方图", Color.FromArgb(255, 0, 0), dhData[2], 256, new float[] { 0.0f, 255.0f }); } else { histogramBox2.AddHistogram("直方图", Color.FromArgb(0, 0, 0), dhData[0], 256, new float[] { 0.0f, 255.0f }); } histogramBox2.Refresh();}private Mat AddMultiHistograms(DenseHistogram[] dh)//此函数功能实现由输入的直方图数据生成Mat图像{ double maxValue = 0; double minValue = 0; if (dh[1] == null)//说明用于计算直方图的图像为单通道 { var arrayData = dh[0].GetBinValues(); maxValue = arrayData.Max(); minValue = arrayData.Min(); for (int i = 0; i < arrayData.Length; i++) { arrayData[i] = (int)((arrayData[i] - minValue) / (maxValue - minValue) * 400.0); } var hist = new Image<Gray, byte>(512, 512, new Gray(255)); Point p1 = new Point(); Point p2 = new Point(); p1.X = 0; p1.Y = 512-(int)arrayData[0]; for (int i = 1; i < arrayData.Length; i++) { p2.X = i*2; p2.Y = 512-(int)arrayData[i]; CvInvoke.Line(hist, p1, p2, new MCvScalar(0),3); p1.X = p2.X; p1.Y = p2.Y; } return hist.Mat; } else { List<float[]> arrayData = new List<float[]> { dh[0].GetBinValues(), dh[1].GetBinValues(), dh[2].GetBinValues() };//颜色顺序BGR maxValue = Math.Max(Math.Max(dh[0].GetBinValues().Max(), dh[1].GetBinValues().Max()), dh[2].GetBinValues().Max()); minValue=Math.Min(Math.Min(dh[0].GetBinValues().Min(), dh[1].GetBinValues().Min()), dh[2].GetBinValues().Min()); for(int index=0;index<arrayData.Count;index++) { for(int i=0;i<arrayData[index].Length;i++) { arrayData[index][i] = (float)((arrayData[index][i] - minValue) / (maxValue - minValue)*400.0); } } var hist = new Image<Bgr, byte>(512, 512, new Bgr(255, 255, 255));//初始化图像 Point p1 = new Point(); Point p2 = new Point(); var colors = new MCvScalar[3] { new MCvScalar(255, 0, 0), new MCvScalar(0, 255, 0), new MCvScalar(0, 0, 255) }; for(int index=0;index<arrayData.Count;index++) { p1.X = 0; p1.Y = 512 - (int)arrayData[index][0]; for(int i=1;i<arrayData[index].Length;i++) { p2.X = i*2; p2.Y = 512 - (int)arrayData[index][i]; CvInvoke.Line(hist, p1, p2, colors[index], 3); p1.X = p2.X; p1.Y = p2.Y; } } return hist.Mat; }}private void button37_Click(object sender, EventArgs e){ if (chapter4Img.IsEmpty) return; var dhData = getDenseHistogramDataOfImage(chapter4Img); var histMat = AddMultiHistograms(dhData); imageBox18.Image = histMat;}
(6)基于查找表的颜色反转
无论是彩色还是单通道都可以哈
//利用查找表反转灰度图像private void button38_Click(object sender, EventArgs e){ if (chapter4Img.IsEmpty) return; Mat lut = new Mat(1, 256, DepthType.Cv8U, 1); byte[] data = new byte[256]; for(int i=0;i<data.Length;i++) { data[i] = (byte)(256 - i); } lut.SetTo(data); Mat resultImg = new Mat(); CvInvoke.LUT(chapter4Img, lut, resultImg); imageBox17.Image = resultImg;}
0 0
- EmguCV学习(二)
- EmguCV学习(一)
- EmguCV学习(三)
- EmguCV学习
- EmguCV的学习日志(一)
- C# + WinForm + EmguCV 学习二:创建和操作图片
- Emgucv图像处理二
- 继续坑自己,EmguCV之SVM.Train(二)
- 【OpenCv/EmguCv】指针式仪表读数(二)
- EmguCV学习-摄像头采集
- EmguCV学习笔记:Image
- EmguCv学习--AdaptiveThreshold函数
- C# EmguCV学习笔记(一)---图像加减法操作
- 【计算机视觉】EmguCV学习笔记(1)Hello World
- EmguCV入门(一)
- 从example开始,学习EmguCV
- EmguCV学习笔记:开篇的话
- 【Emgu】一起学EmguCV(二)Image和Matrix的使用
- spring初步概念(待逐步梳理)
- 你能回答这些问题吗
- mysql 数据类型
- Ubuntu 14.04 Install LAMP Manual
- 面向对象小解
- EmguCV学习(二)
- android中获得全屏显示
- Spring+SpringMVC+MyBaties学习笔记(一)环境搭建
- TTP access control (CORS) 以及 spring 解决方法
- Python爬虫学习笔记一:简单网页图片抓取
- java爬虫 之 搜狐新闻爬虫(一)
- Leetcode题解 217. Contains Duplicate
- nodejs 新建express
- golang 走起(五) Profile 的应用