using System; using System.IO; using System.Drawing; using System.Drawing.Imaging; using System.Collections.Generic; namespace shjxCamera { public class ImageRGBanalysis2 { public ImageRGBanalysis2() { //IsLog = false; } #region properties /// /// 是否写Log /// //public bool IsLog { get; set; } #endregion #region methods public Bitmap CropImage(Bitmap srcImage, Rectangle rcCrop) { BitmapData bmpData = srcImage.LockBits(rcCrop, System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb); Bitmap dstImage = new Bitmap(rcCrop.Width, rcCrop.Height, bmpData.Stride, System.Drawing.Imaging.PixelFormat.Format24bppRgb, bmpData.Scan0); srcImage.UnlockBits(bmpData); return dstImage; } public int GetTotalFromImage(Bitmap srcImage, Rectangle rcCrop, string strChannel = "G") { int channel = 0; // 要提取的颜色通道 switch (strChannel.ToUpper()) { case "B": channel = 0; break; case "G": channel = 1; break; case "R": channel = 2; break; default: channel = 0; break; } if (srcImage.PixelFormat != PixelFormat.Format24bppRgb) { return 0; // 暂时只处理24bit图像 } BitmapData bmpData = srcImage.LockBits(rcCrop, System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb); int totalVal = 0; // 用于统计指定颜色总和 unsafe { byte* pSrc = (byte*)(void*)bmpData.Scan0; for (int i = 0; i < bmpData.Height; i++) { for (int j = 0; j < bmpData.Width; j++) { totalVal += *(pSrc + bmpData.Stride * i + j * 3 + channel); } } } srcImage.UnlockBits(bmpData); return totalVal; } /// /// 写图像指定区域的RGB值到日志文件中 /// /// 图像像素 /// 处理区域 /// 日志标题 public void WriteRGBlog(Bitmap srcImage, Rectangle rcCrop, string title) { if (srcImage == null || srcImage.PixelFormat != PixelFormat.Format24bppRgb) { return; // 暂时只处理24bit图像 } BitmapData bmpData = srcImage.LockBits(rcCrop, System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb); int vr = 0, vg = 0, vb = 0; // 单个像素点 unsafe { string strr = "A:\r\n"; string strg = "B:\r\n"; string strb = "C:\r\n"; List img = new List(); // 用于过滤的像素数据 byte* pSrc = (byte*)(void*)bmpData.Scan0; for (int i = 0; i < bmpData.Height; i++) { for (int j = 0; j < bmpData.Width; j++) { vb = *(pSrc + bmpData.Stride * i + j * 3 + 0); vg = *(pSrc + bmpData.Stride * i + j * 3 + 1); vr = *(pSrc + bmpData.Stride * i + j * 3 + 2); strr = string.Format("{0}{1},", strr, vr.ToString().PadLeft(3, ' ')); strg = string.Format("{0}{1},", strg, vg.ToString().PadLeft(3, ' ')); strb = string.Format("{0}{1},", strb, vb.ToString().PadLeft(3, ' ')); } strr = string.Format("{0}\r\n", strr); strg = string.Format("{0}\r\n", strg); strb = string.Format("{0}\r\n", strb); } #region 将rgb值写入日志 try { string filename = string.Format(@".\log\{0}_pos.txt", DateTime.Now.ToString("yyyyMMdd")); //filename = @".\log\rgbdata_" + DateTime.Now.ToString("yyyyMMdd") + ".txt"; StreamWriter sw = new StreamWriter(filename, true, System.Text.Encoding.Default); sw.WriteLine(DateTime.Now.ToString("yyyyMMdd HH:mm:ss.fff") + " " + title + ":"); ////sw.WriteLine(strr); ////sw.WriteLine(strg); sw.WriteLine(strb); sw.WriteLine(); sw.Close(); } catch (Exception) { } #endregion } srcImage.UnlockBits(bmpData); } /// /// 在左右偏移范围内重新定位目标区域的坐标位置:连续4点相减都满足小于阈值 /// /// 图像像素数据 /// 目标区域 /// 左右偏移查找范围 /// 连续两点之差阈值 /// public Rectangle GetRoiPos2(Bitmap srcImage, Rectangle rcCrop, int offset = 10, int threhold = 3) { Rectangle newRoi = new Rectangle(rcCrop.Location, rcCrop.Size); if (srcImage.PixelFormat != PixelFormat.Format24bppRgb) { return newRoi; // 暂时只处理24bit图像 } BitmapData bmpData = srcImage.LockBits(new Rectangle(0, 0, srcImage.Width, srcImage.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb); int vg1 = 0, vg2 = 0, vg3, vg4 = 0, vg5 = 0; int rowno = (rcCrop.Top + rcCrop.Bottom) / 2; int left = Math.Max(0, (rcCrop.Left - offset)); int right = Math.Min(srcImage.Width - 1, (rcCrop.Right + offset)); unsafe { byte* pSrc = (byte*)(void*)bmpData.Scan0; for (int j = left; j < right; j++) { int istart = bmpData.Stride * rowno + j * 3 + 1; vg1 = *(pSrc + istart + 3 * 0); vg2 = *(pSrc + istart + 3 * 1); vg3 = *(pSrc + istart + 3 * 2); vg4 = *(pSrc + istart + 3 * 3); //vg5 = *(pSrc + istart + 3 * 4); if (vg2 - vg1 >= threhold && vg3 - vg2 >= threhold && vg4 - vg3 >= threhold) { left = j; break; } } for (int j = right; j > left; j--) { int istart = bmpData.Stride * rowno + j * 3 + 1; vg1 = *(pSrc + istart - 3 * 0); vg2 = *(pSrc + istart - 3 * 1); vg3 = *(pSrc + istart - 3 * 2); vg4 = *(pSrc + istart - 3 * 3); //vg5 = *(pSrc + istart - 3 * 4); if (vg2 - vg1 >= threhold && vg3 - vg2 >= threhold && vg4 - vg3 >= threhold) { right = j; break; } } } srcImage.UnlockBits(bmpData); newRoi.X = ((left + right) - rcCrop.Width) / 2 + 1; //PublicDatas.LogProgram.Info(string.Format("found roi left={0}, right={1}", left, right)); return newRoi; } /// /// 以指定值threhold为阈值,找到上下左右边界,然后以此为中心返回新的目标矩形区域 /// /// /// /// /// /// public Rectangle GetRoiPos(Bitmap srcImage, Rectangle rcCrop, int offset, int threhold) { Rectangle newRoi = new Rectangle(rcCrop.Location, rcCrop.Size); if (srcImage.PixelFormat != PixelFormat.Format24bppRgb) { return newRoi; // 暂时只处理24bit图像 } BitmapData bmpData = srcImage.LockBits(new Rectangle(0, 0, srcImage.Width, srcImage.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb); int vg1 = 0, vg2 = 0, vg3, vg4 = 0, vg5 = 0; int top = Math.Max(0, rcCrop.Top - offset); int bottom = Math.Min(srcImage.Height - 1, rcCrop.Bottom + offset); int left = Math.Max(0, (rcCrop.Left - offset)); int right = Math.Min(srcImage.Width - 1, (rcCrop.Right + offset)); unsafe { int pos = 0; // 上边界 byte* pSrc = (byte*)(void*)bmpData.Scan0; for (int i = top; i <= bottom; i++) { for (int j = left; j <= right; j++) { pos = bmpData.Stride * i + j * 3 + 1; vg1 = *(pSrc + pos); if (vg1 >= threhold) { top = i; i = bottom + 1; // 找到边界,终止循环 break; } } } // 下边界 pSrc = (byte*)(void*)bmpData.Scan0; for (int i = bottom; i >= top; i--) { for (int j = left; j <= right; j++) { pos = bmpData.Stride * i + j * 3 + 1; vg1 = *(pSrc + pos); if (vg1 >= threhold) { bottom = i; i = top - 1; // 找到边界,终止循环 break; } } } // 左边界 pSrc = (byte*)(void*)bmpData.Scan0; for (int i = left; i <= right; i++) { for (int j = top; j <= bottom; j++) { pos = bmpData.Stride * j + i * 3 + 1; vg1 = *(pSrc + pos); if (vg1 >= threhold) { left = i; i = right + 1; // 找到边界,终止循环 break; } } } // 右边界 pSrc = (byte*)(void*)bmpData.Scan0; for (int i = right; i >= left; i--) { for (int j = top; j <= bottom; j++) { pos = bmpData.Stride * j + i * 3 + 1; vg1 = *(pSrc + pos); if (vg1 >= threhold) { right = i; i = left - 1; // 找到边界,终止循环 break; } } } } srcImage.UnlockBits(bmpData); newRoi.X = ((left + right) - rcCrop.Width) / 2 + 1; newRoi.Y = ((top + bottom) - rcCrop.Height) / 2 + 1; //PublicDatas.LogProgram.Info(string.Format("found roi left={0}, right={1}, top = {2}, bottom = {3}", left, right, top, bottom)); return newRoi; } /// /// 以图像最大值的1/2作为阈值,找到上下左右边界,然后以此为中心返回新的目标矩形区域 /// /// /// /// /// public Rectangle GetRoiPos(Bitmap srcImage, Rectangle rcCrop, int offset) { Rectangle newRoi = new Rectangle(rcCrop.Location, rcCrop.Size); if (srcImage.PixelFormat != PixelFormat.Format24bppRgb) { return newRoi; // 暂时只处理24bit图像 } BitmapData bmpData = srcImage.LockBits(new Rectangle(0, 0, srcImage.Width, srcImage.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb); int vg1 = 0; int top = Math.Max(0, rcCrop.Top - offset); int bottom = Math.Min(srcImage.Height - 1, rcCrop.Bottom + offset); int left = Math.Max(0, (rcCrop.Left - offset)); int right = Math.Min(srcImage.Width - 1, (rcCrop.Right + offset)); unsafe { int pos = 0; // 找出最大值的1/2作为阈值 double threhold = 0; byte* pSrc = (byte*)(void*)bmpData.Scan0; for (int i = top; i <= bottom; i++) { for (int j = left; j <= right; j++) { pos = bmpData.Stride * i + j * 3 + 0; vg1 = *(pSrc + pos); if (vg1 >= threhold) { threhold = vg1; } } } if (threhold > 0) { threhold = threhold / 2.0; } else { threhold = 10; } //PublicDatas.LogProgram.Debug("自动定位,定位阈值=" + threhold.ToString("F1")); // 上边界 pSrc = (byte*)(void*)bmpData.Scan0; for (int i = top; i <= bottom; i++) { for (int j = left; j <= right; j++) { pos = bmpData.Stride * i + j * 3 + 0; vg1 = *(pSrc + pos); if (vg1 >= threhold) { top = i; i = bottom + 1; // 找到边界,终止循环 break; } } } // 下边界 pSrc = (byte*)(void*)bmpData.Scan0; for (int i = bottom; i >= top; i--) { for (int j = left; j <= right; j++) { pos = bmpData.Stride * i + j * 3 + 0; vg1 = *(pSrc + pos); if (vg1 >= threhold) { bottom = i; i = top - 1; // 找到边界,终止循环 break; } } } // 左边界 pSrc = (byte*)(void*)bmpData.Scan0; for (int i = left; i <= right; i++) { for (int j = top; j <= bottom; j++) { pos = bmpData.Stride * j + i * 3 + 0; vg1 = *(pSrc + pos); if (vg1 >= threhold) { left = i; i = right + 1; // 找到边界,终止循环 break; } } } // 右边界 pSrc = (byte*)(void*)bmpData.Scan0; for (int i = right; i >= left; i--) { for (int j = top; j <= bottom; j++) { pos = bmpData.Stride * j + i * 3 + 0; vg1 = *(pSrc + pos); if (vg1 >= threhold) { right = i; i = left - 1; // 找到边界,终止循环 break; } } } } srcImage.UnlockBits(bmpData); newRoi.X = ((left + right) - rcCrop.Width) / 2 + 1; newRoi.Y = ((top + bottom) - rcCrop.Height) / 2 + 1; //PublicDatas.LogProgram.Info(string.Format("found roi left={0}, right={1}, top = {2}, bottom = {3}", left, right, top, bottom)); return newRoi; } /// /// 在指定的矩形区域内查找大于阈值的像素点的坐标点 /// /// 图像像素数据 /// 指定矩形区域 /// G值的阈值 /// 所有满足要求的坐标点 public List GetRoiMask(Bitmap srcImage, Rectangle rcCrop, double threholdVal = 20) { List roiMask = new List(); if (srcImage.PixelFormat != PixelFormat.Format24bppRgb) { return null; // 暂时只处理24bit图像 } BitmapData bmpData = srcImage.LockBits(rcCrop, System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb); int vg = 0, vr = 0, vb = 0; // 单个像素点 unsafe { byte* pSrc = (byte*)(void*)bmpData.Scan0; for (int i = 0; i < bmpData.Height; i++) { for (int j = 0; j < bmpData.Width; j++) { vb = *(pSrc + bmpData.Stride * i + j * 3 + 0); // 0 //vg = *(pSrc + bmpData.Stride * i + j * 3 + 1); // 1 //vr = *(pSrc + bmpData.Stride * i + j * 3 + 2); // 2 if (vb >= threholdVal) { roiMask.Add(new Point(rcCrop.Left + j, rcCrop.Top + i)); } } } } srcImage.UnlockBits(bmpData); return roiMask; } /// /// 统计指定图像区域的rgb总值 /// /// /// /// /// /// /// 是否使用噪点过滤 /// public bool GetTotalFromImage(Bitmap srcImage, Rectangle rcCrop, ref int sumR, ref int sumG, ref int sumB, NoiseDataFilter2 noiseFilter = null) { if (srcImage is null) throw new ArgumentNullException(nameof(srcImage)); if (srcImage.PixelFormat != PixelFormat.Format24bppRgb) { return false; // 暂时只处理24bit图像 } BitmapData bmpData = srcImage.LockBits(rcCrop, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); sumR = sumG = sumB = 0; // 指定颜色总和 int vr = 0, vg = 0, vb = 0; // 单个像素点 unsafe { int logR = 0, logG = 0, logB = 0; // 统计原始数据的总值,用于写日志 string strr = "R:\r\n"; string strg = "G:\r\n"; string strb = "B:\r\n"; List img = new List(); // 用于过滤的像素数据 byte* pSrc = (byte*)(void*)bmpData.Scan0; for (int i = 0; i < bmpData.Height; i++) { for (int j = 0; j < bmpData.Width; j++) { vb = *(pSrc + bmpData.Stride * i + j * 3 + 0); vg = *(pSrc + bmpData.Stride * i + j * 3 + 1); vr = *(pSrc + bmpData.Stride * i + j * 3 + 2); logB += vb; logG += vg; logR += vr; if (noiseFilter == null) { sumB += vb; sumG += vg; sumR += vr; } else { img.Add(Color.FromArgb(vr, vg, vb)); } /*if (IsLog) { strr = string.Format("{0}{1},", strr, vr.ToString().PadLeft(3, ' ')); strg = string.Format("{0}{1},", strg, vg.ToString().PadLeft(3, ' ')); strb = string.Format("{0}{1},", strb, vb.ToString().PadLeft(3, ' ')); }*/ } /*if (IsLog) { strr = string.Format("{0}\r\n", strr); strg = string.Format("{0}\r\n", strg); strb = string.Format("{0}\r\n", strb); }*/ } #region 将rgb值写入日志 /*if (this.IsLog) { try { string filename = @"d:\log\rgbdata_" + DateTime.Now.ToString("yyyyMMdd") + ".txt"; filename = @"d:\log\rgbdata_" + DateTime.Now.ToString("yyyyMMdd") + ".txt"; StreamWriter sw = new StreamWriter(filename, true, System.Text.Encoding.Default); sw.WriteLine(DateTime.Now.ToString("yyyyMMdd hh:mm:ss.fff") + " 原始数据:"); //sw.WriteLine(strr); sw.WriteLine(strg); //sw.WriteLine(strb); sw.WriteLine(); if (noiseFilter != null) { // 写日志 //noiseFilter.IsLog = true; noiseFilter.swLog = sw; noiseFilter.LogWidth = bmpData.Width; noiseFilter.CalcImage(img, ref sumR, ref sumG, ref sumB); } int tmp = bmpData.Width * bmpData.Height; strr = string.Format("原始总值:(R, G, B)({0}, {1}, {2}), 数据个数:{3}, ", logR, logG, logB, tmp) + string.Format("均值:(R, G, B)({0}, {1}, {2})\r\n", (logR * 1.0 / tmp).ToString("F2"), (logG * 1.0 / tmp).ToString("F2"), (logB * 1.0 / tmp).ToString("F2")); sw.WriteLine(strr); sw.WriteLine(); sw.Close(); } catch (Exception) { } } else { // 不用写日志 if (noiseFilter != null) { noiseFilter.CalcImage(img, ref sumR, ref sumG, ref sumB); } }*/ // 不用写日志 if (noiseFilter != null) { noiseFilter.CalcImage(img, ref sumR, ref sumG, ref sumB); } #endregion } srcImage.UnlockBits(bmpData); return true; } /// /// 根据指定点的坐标队列,计算总值 /// /// /// 计算点的坐标队列 /// /// /// /// /// public bool GetTotalFromImage(Bitmap srcImage, List roiPoint, ref int sumR, ref int sumG, ref int sumB, NoiseDataFilter2 noiseFilter = null) { if (srcImage.PixelFormat != PixelFormat.Format24bppRgb) { return false; // 暂时只处理24bit图像 } BitmapData bmpData = srcImage.LockBits(new Rectangle(0, 0, srcImage.Width, srcImage.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb); sumR = sumG = sumB = 0; // 指定颜色总和 int vr = 0, vg = 0, vb = 0; // 单个像素点 unsafe { int logR = 0, logG = 0, logB = 0; // 统计原始数据的总值,用于写日志 string strr = "R:\r\n"; string strg = "G:\r\n"; string strb = "B:\r\n"; List img = new List(); // 用于过滤的像素数据 byte* pSrc = (byte*)(void*)bmpData.Scan0; foreach (Point pt in roiPoint) { vb = *(pSrc + bmpData.Stride * pt.Y + pt.X * 3 + 0); vg = *(pSrc + bmpData.Stride * pt.Y + pt.X * 3 + 1); vr = *(pSrc + bmpData.Stride * pt.Y + pt.X * 3 + 2); logB += vb; logG += vg; logR += vr; if (noiseFilter == null) { sumB += vb; sumG += vg; sumR += vr; } else { img.Add(Color.FromArgb(vr, vg, vb)); } } #region 将rgb值写入日志 /*if (IsLog) { try { string filename = @"d:\log\rgbdata_" + DateTime.Now.ToString("yyyyMMdd") + ".txt"; filename = @"d:\log\rgbdata_" + DateTime.Now.ToString("yyyyMMdd") + ".txt"; StreamWriter sw = new StreamWriter(filename, true, System.Text.Encoding.Default); sw.WriteLine(DateTime.Now.ToString("yyyyMMdd hh:mm:ss.fff") + " 原始数据:"); sw.WriteLine(strr); sw.WriteLine(strg); sw.WriteLine(strb); sw.WriteLine(); if (noiseFilter != null) { // 写日志 noiseFilter.IsLog = true; noiseFilter.swLog = sw; noiseFilter.LogWidth = bmpData.Width; noiseFilter.CalcImage(img, ref sumR, ref sumG, ref sumB); } int tmp = bmpData.Width * bmpData.Height; strr = string.Format("原始总值:(R, G, B)({0}, {1}, {2}), 数据个数:{3}, ", logR, logG, logB, tmp) + string.Format("均值:(R, G, B)({0}, {1}, {2})\r\n", (logR * 1.0 / tmp).ToString("F2"), (logG * 1.0 / tmp).ToString("F2"), (logB * 1.0 / tmp).ToString("F2")); sw.WriteLine(strr); sw.WriteLine(); sw.Close(); } catch (Exception) { } } else { // 不用写日志 if (noiseFilter != null) { noiseFilter.CalcImage(img, ref sumR, ref sumG, ref sumB); } }*/ #endregion } srcImage.UnlockBits(bmpData); return true; } #endregion } }