视觉基础算法

找到一篇PPT,对于基础知识点的总结比较好,需要自己去深挖知识。链接

一. 图片灰度化

灰度化有多种方式,可以根据自己的需求自己定制,这里列举三种常用的方式。

  1. 将彩色图像的R、G、B三分量的亮度之一作为灰度图像灰度值 Gray=B or Gray=G or Gray=R。
  2. 最大值法:将彩×××像的R、G、B三分量亮度最大值作为灰度图像灰度值max(R,max(G,B)) 注意max函数一次只能比较两个参数;
  3. 加权平均法:将彩×××像的R、G、B三分量以不同的权重进行加权平均。人眼对绿色敏感最高,对蓝色敏感最低,故采用心理学灰度公式:Gray= 0.114B+ 0.587G+ 0.299R 。即是Opencv的颜色空间转换函数 :CV_BGR2GRAY
    加权平均法C#示例代码
        //灰度化public static Bitmap GetGrayImage(Bitmap image){// 如果直接赋值的话,会改变原来的图片。Bitmap result = image.Clone() as Bitmap;Color c = new Color();int ret;for (int i = 0; i < image.Width; i++){for (int j = 0; j < image.Height; j++){c = result.GetPixel(i, j);// 计算点i,j的灰度值ret = (int)(c.R * 0.299 + c.G * 0.587 + c.B * 0.114);result.SetPixel(i, j, Color.FromArgb(ret, ret, ret));}}return result;}

二. 图片锐化

  • 方法壹:将原图像与拉普拉斯模板相乘,再加上原图像。转载自
        private void button13_Click(object sender, EventArgs e) //点击“锐化”控件产生锐化效果{Bitmap myBitmap = new Bitmap(pictureBox1.Image);//建立拉普拉斯模板int[] Laplacian = { -1, -1, -1, -1, 9, -1, -1, -1, -1 };Color pixel;//这里注意边界的像素暂不处理,否则超出数组范围for (int i = 1; i < myBitmap.Width - 1; i++){for (int j = 1; j < myBitmap.Height - 1; j++){int red = 0, green = 0, blue = 0;int index = 0;for (int col = -1; col <= 1; col++) //3*3处理{for (int row = -1; row <= 1; row++){pixel = myBitmap.GetPixel(i + row, j + col);red += pixel.R * Laplacian[index];green += pixel.G * Laplacian[index];blue += pixel.B * Laplacian[index];index++;}}if (red > 255) red = 255;if (red < 0) red = 0;if (green > 255) green = 255;if (green < 0) green = 0;if (blue > 255) blue = 255;if (blue < 0) blue = 0;myBitmap.SetPixel(i-1, j-1, Color.FromArgb((int)red, (int)green, (int)blue)); //这里注意是i-1,j-1,否则效果很糟糕}}pictureBox1.Image = myBitmap;}
  • 方法贰:用当前像素减去周围八个像素的平均值得到差,得到的差值乘以锐化程度,再加原来的像素,得到新的当前像素值。在示例中,由于直接操作内存是不安全的,所以要加unsafe。(来自网络思路)
        /// /// 锐化处理2/// /// 图片/// 锐化程度,值越大程度越大/// public static Bitmap KiSharpen(Bitmap b, float val){if (b == null){return null;}int w = b.Width;int h = b.Height;try{Bitmap bmpRtn = new Bitmap(w, h, PixelFormat.Format24bppRgb);BitmapData srcData = b.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);BitmapData dstData = bmpRtn.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);unsafe{byte* pIn = (byte*)srcData.Scan0.ToPointer();byte* pOut = (byte*)dstData.Scan0.ToPointer();int stride = srcData.Stride;byte* p;for (int y = 0; y < h; y++){for (int x = 0; x < w; x++){//取周围9点的值。位于边缘上的点不做改变。if (x == 0 || x == w - 1 || y == 0 || y == h - 1){//不做pOut[0] = pIn[0];pOut[1] = pIn[1];pOut[2] = pIn[2];}else{int r1, r2, r3, r4, r5, r6, r7, r8, r0;int g1, g2, g3, g4, g5, g6, g7, g8, g0;int b1, b2, b3, b4, b5, b6, b7, b8, b0;float vR, vG, vB;//左上p = pIn - stride - 3;r1 = p[2];g1 = p[1];b1 = p[0];//正上p = pIn - stride;r2 = p[2];g2 = p[1];b2 = p[0];//右上p = pIn - stride + 3;r3 = p[2];g3 = p[1];b3 = p[0];//左侧p = pIn - 3;r4 = p[2];g4 = p[1];b4 = p[0];//右侧p = pIn + 3;r5 = p[2];g5 = p[1];b5 = p[0];//右下p = pIn + stride - 3;r6 = p[2];g6 = p[1];b6 = p[0];//正下p = pIn + stride;r7 = p[2];g7 = p[1];b7 = p[0];//右下p = pIn + stride + 3;r8 = p[2];g8 = p[1];b8 = p[0];//自己p = pIn;r0 = p[2];g0 = p[1];b0 = p[0];vR = (float)r0 - (float)(r1 + r2 + r3 + r4 + r5 + r6 + r7 + r8) / 8;//当前像素-8个的平均vG = (float)g0 - (float)(g1 + g2 + g3 + g4 + g5 + g6 + g7 + g8) / 8;vB = (float)b0 - (float)(b1 + b2 + b3 + b4 + b5 + b6 + b7 + b8) / 8;vR = r0 + vR * val;vG = g0 + vG * val;vB = b0 + vB * val;if (vR > 0){vR = Math.Min(255, vR);}else{vR = Math.Max(0, vR);}if (vG > 0){vG = Math.Min(255, vG);}else{vG = Math.Max(0, vG);}if (vB > 0){vB = Math.Min(255, vB);}else{vB = Math.Max(0, vB);}pOut[0] = (byte)vB;pOut[1] = (byte)vG;pOut[2] = (byte)vR;}pIn += 3;pOut += 3;}// end of xpIn += srcData.Stride - w * 3;pOut += srcData.Stride - w * 3;} // end of y}b.UnlockBits(srcData);          // 释放锁bmpRtn.UnlockBits(dstData);return bmpRtn;}catch{return null;}} 
  • 方法叁:将像素从内存中拷贝出来操作完后再重新赋值,以达到对图像的快速读取和处理。(程序源自网络)
        public static Bitmap SharpenImage(Bitmap bmp){int height = bmp.Height;int width = bmp.Width;Bitmap newbmp = new Bitmap(width, height);LockBitmap lbmp = new LockBitmap(bmp);LockBitmap newlbmp = new LockBitmap(newbmp);lbmp.LockBits();newlbmp.LockBits();Color pixel;//拉普拉斯模板int[] Laplacian = { -1, -1, -1, -1, 9, -1, -1, -1, -1 };for (int x = 1; x < width - 1; x++){for (int y = 1; y < height - 1; y++){int r = 0, g = 0, b = 0;int Index = 0;for (int col = -1; col <= 1; col++){for (int row = -1; row <= 1; row++){pixel = lbmp.GetPixel(x + row, y + col);r += pixel.R * Laplacian[Index];g += pixel.G * Laplacian[Index];b += pixel.B * Laplacian[Index];Index++;}}//处理颜色值溢出r = r > 255 ? 255 : r;r = r < 0 ? 0 : r;g = g > 255 ? 255 : g;g = g < 0 ? 0 : g;b = b > 255 ? 255 : b;b = b < 0 ? 0 : b;newlbmp.SetPixel(x - 1, y - 1, Color.FromArgb(r, g, b));}}lbmp.UnlockBits();newlbmp.UnlockBits();return newbmp;}
/// 
/// 快速读取像素和处理
/// 
public class LockBitmap
{Bitmap source = null;IntPtr Iptr = IntPtr.Zero;BitmapData bitmapData = null;public byte[] Pixels { get; set; }public int Depth { get; private set; }public int Width { get; private set; }public int Height { get; private set; }public LockBitmap(Bitmap source)    // 初始化,传递bitmap图片{this.source = source;}/// /// Lock bitmap data/// public void LockBits(){try{// Get width and height of bitmapWidth = source.Width;Height = source.Height;// get total locked pixels count   获取所有的像素点int PixelCount = Width * Height;// Create rectangle to lock      画矩形,传两个坐标位置Rectangle rect = new Rectangle(0, 0, Width, Height);// get source bitmap pixel format size    获取指定格式像素的颜色深度// PixelFormat: (指定图像中每个像素的颜色数据的格式)Depth = System.Drawing.Bitmap.GetPixelFormatSize(source.PixelFormat);// Check if bpp (Bits Per Pixel) is 8, 24, or 32if (Depth != 8 && Depth != 24 && Depth != 32){throw new ArgumentException("Only 8, 24 and 32 bpp images are supported.");}// Lock(锁) bitmap and return bitmap databitmapData = source.LockBits(rect, ImageLockMode.ReadWrite,                          source.PixelFormat);// create byte array to copy pixel valuesint step = Depth / 8;Pixels = new byte[PixelCount * step];Iptr = bitmapData.Scan0;// Copy data from pointer to arrayMarshal.Copy(Iptr, Pixels, 0, Pixels.Length);}catch (Exception ex){throw ex;}}/// /// Unlock bitmap data/// public void UnlockBits(){try{// Copy data from byte array to pointerMarshal.Copy(Pixels, 0, Iptr, Pixels.Length);// Unlock bitmap datasource.UnlockBits(bitmapData);}catch (Exception ex){throw ex;}}/// /// Get the color of the specified pixel/// /// /// /// public Color GetPixel(int x, int y){Color clr = Color.Empty;// Get color components countint cCount = Depth / 8;// Get start index of the specified pixelint i = ((y * Width) + x) * cCount;if (i > Pixels.Length - cCount)throw new IndexOutOfRangeException();if (Depth == 32) // For 32 bpp get Red, Green, Blue and Alpha{byte b = Pixels[i];byte g = Pixels[i + 1];byte r = Pixels[i + 2];byte a = Pixels[i + 3]; // aclr = Color.FromArgb(a, r, g, b);}if (Depth == 24) // For 24 bpp get Red, Green and Blue{byte b = Pixels[i];byte g = Pixels[i + 1];byte r = Pixels[i + 2];clr = Color.FromArgb(r, g, b);}if (Depth == 8)// For 8 bpp get color value (Red, Green and Blue values are the same){byte c = Pixels[i];clr = Color.FromArgb(c, c, c);}return clr;}/// /// Set the color of the specified pixel/// /// /// /// public void SetPixel(int x, int y, Color color){// Get color components countint cCount = Depth / 8;// Get start index of the specified pixelint i = ((y * Width) + x) * cCount;if (Depth == 32) // For 32 bpp set Red, Green, Blue and Alpha{Pixels[i] = color.B;Pixels[i + 1] = color.G;Pixels[i + 2] = color.R;Pixels[i + 3] = color.A;}if (Depth == 24) // For 24 bpp set Red, Green and Blue{Pixels[i] = color.B;Pixels[i + 1] = color.G;Pixels[i + 2] = color.R;}if (Depth == 8)// For 8 bpp set color value (Red, Green and Blue values are the same){Pixels[i] = color.B;}}
}

三. 二值化

  • 二值化:将图片各像素按照阈值设定为255(纯白)、0(纯黑)两种状态,对于自适应阈值的设定可以按照自己的需求进行修改。(示例来源网络,自己添加注释,如有错误请留言)
        public static Bitmap DoThresholdings1(Bitmap img1, int threshold){int w = img1.Width;int h = img1.Height;Bitmap dstBitmap = new Bitmap(w, h, PixelFormat.Format24bppRgb);int[] histogram = new int[256];int minGrayValue = 255, maxGrayValue = 0;//求取直方图for (int i = 0; i < w; i++){for (int j = 0; j < h; j++){Color pixelColor = img1.GetPixel(i, j); // 获取像素点histogram[pixelColor.R]++;              // R通道每个值的个数,if (pixelColor.R > maxGrayValue) maxGrayValue = pixelColor.R;       // 计算最大值if (pixelColor.R < minGrayValue) minGrayValue = pixelColor.R;       // 计算最小值}}//迭代计算阀值if (threshold == -1){int newThreshold = (minGrayValue + maxGrayValue) / 2;           // 求平均for (int iterationTimes = 0; threshold != newThreshold && iterationTimes < 100; iterationTimes++){threshold = newThreshold;int lP1 = 0;int lP2 = 0;int lS1 = 0;int lS2 = 0;//求两个区域的灰度的平均值for (int i = minGrayValue; i < threshold; i++){lP1 += histogram[i] * i;            // histogram[i]:像素i的个数,i:像素值; lP1:所有像素乘个数的和lS1 += histogram[i];                // 共有的像素个数}int mean1GrayValue = (lP1 / lS1);       // 平均像素:x = ( x1*w1 + x2*w2+...+xn*wn ) / (w1 + w2 +...+ wn)for (int i = threshold + 1; i < maxGrayValue; i++){lP2 += histogram[i] * i;lS2 += histogram[i];}int mean2GrayValue = (lP2 / lS2);newThreshold = (mean1GrayValue + mean2GrayValue) / 2;}}//MessageBox.Show(threshold.ToString());//计算二值化for (int i =0; i < w; i++){for (int j = 0; j < h; j++){Color pixelColor = img1.GetPixel(i, j);if (pixelColor.R > threshold){dstBitmap.SetPixel(i, j, Color.FromArgb(255, 255, 255));        // 二值化赋值//Console.WriteLine("白色区域位置:{0},{1}", i, j);}else{dstBitmap.SetPixel(i, j, Color.FromArgb(0, 0, 0));//Console.WriteLine("黑色区域位置:{0},{1}", i, j);}}}return dstBitmap;}
  • 全局平均值二值化:计算全图平均值,按照平均值进行二值化赋值。
    具体例程如下,相对简单:
            /// /// 平均值法获取二值化的阈值/// /// 灰度图像/// public static Bitmap GetBinaryzationImage1(Bitmap image){Bitmap result = image.Clone() as Bitmap;// 计算灰度平均值List<int> tempList = new List<int>();for (int i = 0; i < result.Width; i++){for (int j = 0; j < result.Height; j++){tempList.Add(result.GetPixel(i, j).R);          // 将R通道的像素加入到列表中}}double average = tempList.Average();                    // 计算列表的所有像素的平均值Color color = new Color();for (int i = 0; i < result.Width; i++){for (int j = 0; j < result.Height; j++){color = result.GetPixel(i, j);if ((color.R + color.G + color.B) / 3 > average)// 三通道平均值和全图像素平均值做比较,再进行二值化赋值 {result.SetPixel(i, j, Color.White);             }else{result.SetPixel(i, j, Color.Black);}}}return result;}

四. 图像边缘检测

  • Canny算子(程序如下,原理后续补齐)。
  • 网上找到一篇不错的博文。链接
    //Canny算子public class Canny{public Bitmap _bitmap;public Canny(Bitmap _bitmap){this._bitmap = _bitmap;}public static Image CannyProcess(Bitmap src, int highThreshould, int lowThreshould){if (src != null){int w = src.Width;int h = src.Height;byte[] temp = Bitmap2Bytes(src);byte[] tempMask = (byte[])temp.Clone();int[,] srcBytes = new int[w, h];for (int j = 0; j < h; j++)//转灰度{for (int i = 0; i < w; i++){srcBytes[i, j] = (int)(tempMask[i * 4 + j * w * 4] * 0.114 +tempMask[i * 4 + 1 + j * w * 4] * 0.587 +tempMask[i * 4 + 2 + j * w * 4] * 0.299);}}float gradientMax = 100;float[,] gradient = new float[w, h];//梯度数组byte[,] degree = new byte[w, h];//梯度角度数组GaussFilter(ref srcBytes, w, h);//高斯平滑                GetGradientDegree(srcBytes, ref gradient, ref degree, ref gradientMax, w, h);//计算梯度NonMaxMini(gradient, ref srcBytes, gradientMax, w, h, degree);//非极大值抑制                               TwoThreshouldJudge(highThreshould, lowThreshould, ref srcBytes, w, h);byte bytex;Bitmap dstBitmap = new Bitmap(w, h, PixelFormat.Format24bppRgb);for (int j = 0; j < h; j++){for (int i = 0; i < w; i++){bytex = (byte)srcBytes[i, j];dstBitmap.SetPixel(i, h - j - 1, Color.FromArgb(bytex, bytex, bytex));}}return dstBitmap;}else{return null;}}//高斯滤波private static void GaussFilter(ref int[,] src, int x, int y){for (int j = 1; j < y - 1; j++){for (int i = 1; i < x - 1; i++){src[i, j] = (4 * src[i, j] + src[i - 1, j - 1] + src[i + 1, j - 1] + src[i - 1, j + 1] + src[i + 1, j + 1] + 2 * src[i, j - 1] + 2 * src[i - 1, j] + 2 * src[i, j + 1] + 2 * src[i + 1, j]) / 16;}}}//梯度相位角获取private static void GetGradientDegree(int[,] srcBytes, ref float[,] gradient, ref byte[,] degree, ref float GradientMax, int x, int y){gradient = new float[x, y];degree = new byte[x, y];int gx, gy;int temp;double div;for (int j = 1; j < y - 1; j++){for (int i = 1; i < x - 1; i++){gx = srcBytes[i + 1, j - 1] + 2 * srcBytes[i + 1, j] + srcBytes[i + 1, j + 1] - srcBytes[i - 1, j - 1] - 2 * srcBytes[i - 1, j] - srcBytes[i - 1, j + 1];gy = srcBytes[i - 1, j - 1] + 2 * srcBytes[i, j - 1] + srcBytes[i + 1, j - 1] - srcBytes[i - 1, j + 1] - 2 * srcBytes[i, j + 1] - srcBytes[i + 1, j + 1];gradient[i, j] = (float)Math.Sqrt((double)(gx * gx + gy * gy));if (GradientMax < gradient[i, j]){GradientMax = gradient[i, j];}if (gx == 0){temp = (gy == 0) ? 0 : 90;}else{div = (double)gy / (double)gx;if (div < 0){temp = (int)(180 - Math.Atan(-div) * 180 / Math.PI);}else{temp = (int)(Math.Atan(div) * 180 / Math.PI);}if (temp < 22.5){temp = 0;}else if (temp < 67.5){temp = 45;}else if (temp < 112.5){temp = 90;}else if (temp < 157.5){temp = 135;}elsetemp = 0;}degree[i, j] = (byte)temp;}}}//非极大值抑制private static void NonMaxMini(float[,] gradient, ref int[,] srcBytes, float GradientMax, int x, int y, byte[,] degree){float leftPixel = 0, rightPixel = 0;for (int j = 1; j < y - 1; j++){for (int i = 1; i < x - 1; i++){switch (degree[i, j]){case 0:leftPixel = gradient[i - 1, j];rightPixel = gradient[i + 1, j];break;case 45:leftPixel = gradient[i - 1, j + 1];rightPixel = gradient[i + 1, j - 1];break;case 90:leftPixel = gradient[i, j + 1];rightPixel = gradient[i, j - 1];break;case 135:leftPixel = gradient[i + 1, j + 1];rightPixel = gradient[i - 1, j - 1];break;default:break;}if ((gradient[i, j] < leftPixel) || (gradient[i, j] < rightPixel)){srcBytes[i, j] = 0;}else{int xx = (int)(255 * gradient[i, j] / GradientMax);srcBytes[i, j] = xx;}}}}//双阈值边缘判断private static void TwoThreshouldJudge(int highThreshold, int lowThreshould, ref int[,] srcBytes, int x, int y){for (int j = 1; j < y - 1; j++){for (int i = 1; i < x - 1; i++){if (srcBytes[i, j] > highThreshold){srcBytes[i, j] = 255;}else if (srcBytes[i, j] < lowThreshould){srcBytes[i, j] = 0;}else{if (srcBytes[i - 1, j - 1] < highThreshold && srcBytes[i, j - 1] < highThreshold && srcBytes[i + 1, j - 1] < highThreshold && srcBytes[i - 1, j] < highThreshold&& srcBytes[i + 1, j] < highThreshold && srcBytes[i - 1, j + 1] < highThreshold && srcBytes[i, j + 1] < highThreshold && srcBytes[i + 1, j + 1] < highThreshold){srcBytes[i, j] = 0;}elsesrcBytes[i, j] = 255;}}}}public static byte[] Bitmap2Bytes(Bitmap b){MemoryStream ms = new MemoryStream();b.Save(ms, ImageFormat.Bmp);byte[] bytes = ms.GetBuffer();ms.Close();return bytes;}public static Bitmap Bytes2Bitmap(byte[] bytes, int w, int h){MemoryStream ms1 = new MemoryStream(bytes, 0, w * 4 * h);Bitmap bm = (Bitmap)Image.FromStream(ms1);ms1.Close();return bm;}}


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部