/// <summary> /// 二次精确定位 /// </summary> /// <param name="PicMap">传入图像</param> /// <returns></returns> public Rectangle GetSubImg(GrayImg PicMap) { int[] level, vertical; //GetWPojl(PicMap, out level); GetWPojv(PicMap, out vertical); EdgeY(PicMap, out level); Rectangle result = new Rectangle(vertical[0], level[0], vertical[1] - vertical[0], level[1] - level[0]); return result; }
/// <summary> /// 确定车牌水平边界 /// </summary> /// <param name="psi">待投影灰度图</param> /// <param name="PW">水平边界</param> /// public void GetWPojv(GrayImg psi, out int[] Edge) { //int MaxValue = 0; int Width = psi.Width; int Height = psi.Height; int[] PW = new int[Width]; Edge = new int[2]; for (int y = 0; y < Height; y++) { for (int x = 0; x < Width; x++) { PW[x] += psi.Img[y * Width + x]; } } int i = 0; while (PW[i] < 255 * 5) i++; if (PW[i] != 0 && i < Width) { Edge[0] = i; i = Width - 1; while (PW[i] < 255 * 5 && i > 0) i--; if (PW[i] != 0) Edge[1] = i; } return; }
/// <summary> /// 切割图片提取特征码 /// </summary> /// <param name="SW">横向切割条数,一般情况下将切割分为20×20</param> /// <param name="SH">纵向切割条数</param> public int Eigenvalue(int SW, int SH, out byte[] EMatrix, GrayImg inBase) { float Wsmall = (float)inBase.Width / (float)SW; float Hsmall = (float)inBase.Height / (float)SH; EMatrix = new byte[SW * SH]; for (int y = 0; y < SH; y++) { for (int x = 0; x < SW; x++) { /*统计黑点个数,超过40%则将其定为1*/ int cout = 0; for (int y1 = (int)(y * Hsmall); y1 < (int)((y + 1) * Hsmall); y1++) { for (int x1 = (int)(x * Wsmall); x1 < (int)((x + 1) * Wsmall); x1++) { if (inBase.Img[y1 * inBase.Width + x1] == 255) cout++; } } if (cout >= Wsmall * Hsmall / 2) EMatrix[y * SW + x] = 1; else EMatrix[y * SW + x] = 0; } } return 1; }
public IrisLocation findIris(GrayImg inBase) { Circle p = findPupil(inBase, 1, 1.0D); Circle l = findLimbus(inBase, p, 7, 10D); IrisLocation i = new IrisLocation(); i.limbus = ScaleCircle(l, 1); i.pupil = ScaleCircle(p, 1); return i; }
/// <summary> /// 图像二值化——大津法 /// </summary> /// <param name="thresh">传出计算出的阈值</param> public static int BinaryImg(GrayImg inBase) { int thresh = 128; double mean1, mean2; int noudo1 = 0, noudo2 = 0; int th, level = 0; //求最高灰度级 byte fmax = 255, fmin = 0; Bright_Range(out fmax, out fmin, inBase); int level1 = (int)fmin; level = (int)fmax; /*th循环开始,小于阈值th的像素归为第一类,大于th的像素归为第二类th=0,1,...,level*/ int allPiexl = inBase.Width * inBase.Height; double bunsan = 0; thresh = 0; for (th = level1; th <= level; th++) { noudo1 = noudo2 = 0; int gasosu1 = 0, gasosu2 = 0; for (int i = 0; i < allPiexl; i++) { if (inBase.Img[i] < th) { gasosu1++; noudo1 += inBase.Img[i]; } if (inBase.Img[i] >= th) { gasosu2++; noudo2 += inBase.Img[i]; } } if (gasosu1 > 0) mean1 = (double)((double)noudo1 / gasosu1); else mean1 = 0; if (gasosu2 > 0) mean2 = (double)((double)noudo2 / gasosu2); else mean2 = 0; double bunsantmp = (double)gasosu1 * gasosu2 * (mean1 - mean2) * (mean1 - mean2); if (bunsantmp > bunsan) { bunsan = bunsantmp; thresh = th; } } return thresh; }
/// <summary> /// 高通滤波 /// </summary> /// <param name="PicMap"></param> /// <param name="n">滤波次数</param> public void HighFilter(GrayImg PicMap, int n) { int i, j, Width, Height, nWidth, nHeight; Width = PicMap.Width; Height = PicMap.Height; nWidth = Width / 2; nHeight = Height / 2; int lLineBytes = (Width * 3 + 3) / 4 * 4; WaveOnce(PicMap, n); for (j = (int)(Height * (1 - 1 / Math.Pow(2, (n - 1)))); j < Height; j++) { for (i = 0; i < Width / Math.Pow(2, n); i++) { PicMap.Img[j * Width + i] = (byte)128; } } IDWT(PicMap, n); }
public void generateCode(GrayImg inBase, bool isTrim) { int width = inBase.Width; int height = inBase.Height; int[,] unrolled2d = new int[width, height]; for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { unrolled2d[x, y] = (int)inBase.Img[y * width + x]; } } applyFilter(3, 2, unrolled2d, 0.2F, 0.05F); int[,] imgarr = isTrim ? trimArr(iout) : iout; byte[] output = thresholdImageData(imgarr); ICode = new IrisCode(output, imgarr.GetLength(0), imgarr.GetLength(1)); int[,] realarr = isTrim ? trimArr(rout) : rout; byte[] output1 = thresholdImageData(realarr); RCode = new IrisCode(output1, realarr.GetLength(0), imgarr.GetLength(1)); }
/// <summary> /// 生成车牌垂直投影 /// </summary> /// <param name="pVProject"></param> /// <param name="pSrcImg"></param> /// <param name="FilterTH"></param> private void VProjectImg(ref int[] pVProject, GrayImg pSrcImg, int FilterTH) { for (int i = 0; i < pSrcImg.Width; i++) { for (int j = 0; j < pSrcImg.Height; j++) { if (pSrcImg.Img[j * pSrcImg.Width + i] == 255) pVProject[i]++; } } //投影过滤 for (int i = 0; i < pSrcImg.Width; i++) { if (pVProject[i] < FilterTH) pVProject[i] = 0; } }
/// <summary> /// 确定车牌垂直边界 /// </summary> /// <param name="psi">待投影灰度图</param> /// <param name="PW">垂直边界</param> /// public void GetWPojl(GrayImg psi, out int[] Edge) { //int MaxValue = 0; int Width = psi.Width; int Height = psi.Height; int[] PW = new int[Height]; int low = 0, high = Height - 1; double sum = 0; //垂直边界 Edge = new int[2]; for (int y = 0; y < Height; y++) { for (int x = 0; x < Width; x++) { PW[y] += psi.Img[y * Width + x]; } if (PW[y] > sum) sum = PW[y]; } //for ( int i = 0; i < Height; i++) // sum += PW[i]; sum = sum * 0.35; while (low + high * 0.6 < high) { if (PW[low] < sum) { Edge[0] = low; low++; } else low++; if (PW[high] < sum) { Edge[1] = high; high--; } else high--; } }
/// <summary> /// 获取子图 /// </summary> /// <param name="pDestImg">目标图像</param> /// <param name="pSrcImg">源图像</param> /// <param name="rect">截取区域</param> /// <returns></returns> public static int GetSubImg(out PICLib.GrayImg pDestImg, GrayImg pSrcImg, Rectangle rect) { PicBase.ImgMalloc(out pDestImg, rect.Width, rect.Height); for (int y = rect.Top; y < rect.Top + rect.Height; y++) { for (int x = rect.Left; x < rect.Left + rect.Width; x++) { pDestImg.Img[(y - rect.Top) * rect.Width + (x - rect.Left)] = pSrcImg.Img[y * pSrcImg.Width + x]; } } return 1; }
/// <summary> /// 字符切割 /// </summary> /// <param name="PicMap">传入车牌图像</param> /// <param name="CountRegion">字符所在水平区间</param> /// <param name="Value">canny算子处理后图像垂直投影数组</param> public static void CutChar(GrayImg PicMap, out extent[] CountRegion, int[] Value) { //Result = new GrayImg[7]; int Length = Value.Length; int[] Count = new int[60]; int curr = 1; int i; ////抹去第三个位置的小数点 //for (i = 55; i < 80; i++) //{ // if (Value[i] < 10) // Value[i] = 0; //} //for (int i = 0; i < Length; i++) //{ //if (Value[i] == 0) //{ // Count[curr] = i; // curr++; // Count[0]++; // i++; // while (Value[i] == 0 && i < Length) // i++; // if (Value[i] != 0 && i < Length) // { // Count[curr] = i; // curr++; // } //} //else // i++; //} i = 0; while (i < Length) { //寻找可能为字符区域的左边界 while (i < Length && Value[i] == 0) i++; if (i < Length) { Count[curr] = i; curr++; Count[0]++; i++; } else break; //寻找为可能为字符区域的右边界 while (i < Length && Value[i] != 0) i++; if (i < Length) { Count[curr] = i - 1; curr++; //Count[0]++; } else break; } CountRegion = new extent[Count[0]]; for (i = 0; i < Count[0]; i++) { CountRegion[i].Start = Count[2 * i + 1]; CountRegion[i].End = Count[2 * i + 2]; } if (CountRegion[Count[0] - 1].End == 0) CountRegion[Count[0] - 1].End = Value.Length - 1; //去除大边缘小面积噪音 i = 0; while (i < CountRegion.Length && CountRegion[i].End - CountRegion[i].Start < 8) { CountRegion[i].End = CountRegion[i].Start; i++; } //去除左边缘较大面积噪音 if (i < CountRegion.Length && CountRegion[i].End - CountRegion[i].Start < 13 && CountRegion[i + 1].End - CountRegion[i + 1].Start > 17) { CountRegion[i].End = CountRegion[i].Start; i++; } //处理字母被切割成两部分 i++; if (i < CountRegion.Length - 1 && CountRegion[i + 1].End - CountRegion[i].Start > 18 && CountRegion[i + 1].End - CountRegion[i].Start < 36 && CountRegion[i].End - CountRegion[i].Start < 18) { CountRegion[i].End = CountRegion[i + 1].End; CountRegion[i + 1].End = CountRegion[i + 1].Start; i++; } i++; if (i < CountRegion.Length && CountRegion[i].End - CountRegion[i].Start < 10 && CountRegion[i].End - CountRegion[i].Start > 0) { int sum = 0; for (int temp = CountRegion[i].Start; temp <= CountRegion[i].End; temp++) { sum += Value[temp]; } sum /= (CountRegion[i].End - CountRegion[i].Start); if (sum < 10) { CountRegion[i].End = CountRegion[i].Start; i++; } } while (i < CountRegion.Length) { if (CountRegion[i].End - CountRegion[i].Start < 8 && CountRegion[i].End - CountRegion[i].Start != 0) { int sum = 0; for (int temp = CountRegion[i].Start; temp <= CountRegion[i].End; temp++) { sum += Value[temp]; } sum /= (CountRegion[i].End - CountRegion[i].Start); if (sum < 10) { CountRegion[i].End = CountRegion[i].Start; i++; } else i++; } else i++; } //i = 0; //while (!(CountRegion[i].End > 50)) // i++; //int CountLeft =0; ////寻找前两个字符区间 //for (int Now = i; curr > 0; curr--) //{ // //区域不足以构成一个字符 // if (CountRegion[Now].End - CountRegion[Now].Start < 18 && Now > 0) // { // CountRegion[Now - 1].End = CountRegion[Now].End; // CountRegion[Now].Start = CountRegion[Now].End; // CountLeft++; // } // else if (CountLeft == 2) // { // CountRegion[Now].End = CountRegion[Now].Start; // } // else // CountLeft++; //} ////处理第三个区域为小数点情况 //i++; //while (CountRegion[i].End - CountRegion[i].Start < 10 && CountRegion[i].End - CountRegion[i].Start > 0) //{ // int Avg = 0; // for (int temp = CountRegion[i + 1].Start; temp <= CountRegion[i + 1].End; temp++) // Avg += Value[temp]; // Avg /= (CountRegion[i].End - CountRegion[i].Start); // if (Avg < 15) // i++; //} ////寻找后五个字符区间 //i += 5; //while (i < CountRegion.Length) //{ // CountRegion[i].End = CountRegion[i].Start; // i++; //} }
/// <summary> /// 生成垂直投影 /// </summary> /// <param name="psi">待投影灰度图</param> /// <param name="PW">投影数组</param> /// public static void GetWPojX(GrayImg psi, out int[] PW, out int MaxValue) { MaxValue = 0; int Width = psi.Width; int Height = psi.Height; PW = new int[Width]; for (int x = 0; x < Width; x++) { for (int y = 0; y < Height; y++) { PW[x] += psi.Img[y * Width + x]; if (PW[x] > MaxValue) MaxValue = PW[x]; } } MaxValue /= 255; for (int i = 0; i < Width; i++) { PW[i] /= 255; //去掉中间的小数点"." //if (PW[i] < 10&& i > 55 && i < 80) // PW[i] = 0; } ////附加统计内容 //int count = 0; //for (int i = 0; i < Width; i++) //{ // if (PW[i] == 0) // { // count++; // } // else // count = 0; // if (count > 10) // { // PW[i] = MaxValue; // count = 0; // } //} return; }
/// <summary> /// 确定车牌垂直边界 /// </summary> /// <param name="PicMap"></param> /// <param name="Edge">垂直边界</param> public void EdgeY(GrayImg PicMap, out int[] Edge) { int Height = PicMap.Height; int Width = PicMap.Width; int MaxValue = 0; Edge = new int[2]; Edge[1] = Height - 1; int[] PW = new int[Height]; for (int i = 0; i < Height; i++) { // MaxValue = 0; for (int j = 0; j < Width - 1; j++) { if ((PicMap.Img[i * Width + j] - PicMap.Img[i * Width + j + 1]) != 0) { PW[i]++; } } if (PW[i] > MaxValue) MaxValue = PW[i]; } int low = 0; int high = Height - 1; MaxValue = (int)(MaxValue * 0.4); while (low != high && low < high) { if (PW[low] < MaxValue) { Edge[0] = low; low++; } else low++; if (PW[high] < MaxValue) { Edge[1] = high; high--; } else high--; } }
/// <summary> /// 一次精定位 /// </summary> /// <param name="pSrcImg"></param> /// <returns></returns> public Rectangle GetLP_1(GrayImg pSrcImg) { Rectangle retRect = new Rectangle(0, 0, pSrcImg.Width, pSrcImg.Height); /*定义一个矩形区域*/ int[] pHProject = new int[pSrcImg.Height]; //获取垂直投影 HProjectImg(ref pHProject, pSrcImg, pltVMin); //初判断车牌水平位置 int pDownYPos = pSrcImg.Height, pUpYPos = 0; ArrayList WaveCollect = new ArrayList(); bool Flag = true; UnitWave aWave = new UnitWave(); for (int y = pDownYPos - 1; y >= pUpYPos; y--) { if (pHProject[y] != 0 && Flag) { aWave.Endw = y; Flag = false; } if (pHProject[y] == 0 && (!Flag)) { aWave.Startw = y; WaveCollect.Add(aWave); aWave = new UnitWave(); Flag = true; } } if (!Flag) { aWave.Startw = 0; WaveCollect.Add(aWave); } if (WaveCollect.Count <= 0) { return retRect; } /*开始过滤,过滤车牌靠上与靠下,与高度不够或高度过高的情况*/ for (int i = WaveCollect.Count - 1; i >= 0; i--) { UnitWave aunit = (UnitWave)WaveCollect[i]; if (aunit.Startw < HStartPosition || aunit.Endw > HEndPosition || aunit.GetWaveLen() < PltHMin || aunit.GetWaveLen() > PltHMax) { WaveCollect.RemoveAt(i); } } int tmp = 0; /*开始针对每一组区域定位车牌水平区域*/ for (int i = 0; i < WaveCollect.Count; i++) { UnitWave aunit = (UnitWave)WaveCollect[i]; //获取区域 Rectangle rect = new Rectangle(0, aunit.Startw, pSrcImg.Width, aunit.GetWaveLen()); GrayImg tmpRect; Process.GetSubImg(out tmpRect, pSrcImg, rect); int[] pVProject = new int[tmpRect.Width]; //计算过滤因子 int th = (int)(0.16f * tmpRect.Height); VProjectImg(ref pVProject, tmpRect, th); int LDentisty = 0; int StartX = PXStart; for (int i1 = PXStart; i1 < pSrcImg.Width - EPWidth; i1++) { if (pVProject[i1] == 0) { continue; } else { int tempdet = 0; //计算区域线密度,并将最大线密度存入临时变量 for (int p = i1; p < i1 + EPWidth; p++) { if (pVProject[p] != 0) { tempdet++; } } if (tempdet > LDentisty) { LDentisty = tempdet; StartX = i1; } } } //获取区域 Rectangle rect1 = new Rectangle(StartX, aunit.Startw, EPWidth, aunit.GetWaveLen()); Process.GetSubImg(out tmpRect, pSrcImg, rect1); //对区域作二次投影分析 int[] PVrect = new int[tmpRect.Width]; th = (int)(0.16f * tmpRect.Height); VProjectImg(ref PVrect, tmpRect, th); //计算投影中有多少有效列 int n = 0; for (int x = 0; x < tmpRect.Width; x++) { if (PVrect[x] != 0) { n++; } } int wfmax = (int)((float)tmpRect.Width * 1.0f); int wfmin = (int)((float)tmpRect.Width * 0.15f); //如果线过密或过稀疏,则不是车牌 if (n > wfmax || n < wfmin) { continue; } else { if (n > tmp) { retRect = rect1; tmp = n; } } } if (retRect.Width != pSrcImg.Width) { retRect.X -= 10; retRect.Y -= 5; retRect.Width += 20; retRect.Height += 10; } return retRect; }
/// <summary> /// 以车牌图像为原始图像进行字符切割 /// </summary> /// <param name="PicMap">Canny算子处理后结果</param> /// <param name="Result">各个字符水平起始位置</param> public GrayImg[] CutCharOld(GrayImg R2tmp) { GrayImg[] Chars; int[] PH2, PH3; //传入图像副本 GrayImg R3tmp; //二值化 int Yz1 = Process.BinaryImg(R2tmp); Process.BinaryImg(R2tmp, out R2tmp, Yz1); //对传入车牌图像进行闭运算 Process.Closing_8(out R2tmp, R2tmp); PicBase.ImgClone(out R3tmp, R2tmp); ////反色 //Invert(out R3tmp, R3tmp); //将车牌放大至标准 Process.Zoomup(out R3tmp, R3tmp, 200, 40); Process.Zoomup(out R2tmp, R2tmp, 200, 40); //////LoadSP(R3tmp, PictureBoxSizeMode.Normal, "再放大至标准"); //////LoadSP(gryImgtmp2, PictureBoxSizeMode.Normal, "再放大至标准"); //对车牌区域进行垂直投影 Process.GetHPoj(R2tmp, out PH2); //做水平边缘检测 int[] TemplateArr2 = new int[9] { 1, 4, 1, 0, 0, 0, -1, -4, -1 }; Process.Template(out R2tmp, R2tmp, TemplateArr2, 3, 1); //再二值化 //二值化 int Yz2 = Process.BinaryImg(R2tmp); Process.BinaryImg(R2tmp, out R2tmp, Yz2); //LoadSP(R2tmp, PictureBoxSizeMode.Normal, "水平边缘检测"); Process.GetHPoj(R2tmp, out PH3); /*两个波形做一次与运算*/ int[] PHCombine = new int[PH2.Length]; for (int ws = 0; ws < PH2.Length; ws++) { //if (PH2[ws] != 0 && PH3[ws] != 0) if (Math.Abs(PH2[ws] - PH3[ws]) <= 18 && PH3[ws] > 4) PHCombine[ws] = R2tmp.Height; } /*通过组合投影卡定车牌左定位*/ LocVPlateLeft(out R3tmp, R3tmp, PHCombine, ref R2tmp); ////LoadSP(R3tmp, PictureBoxSizeMode.AutoSize, "垂直精确定位车牌:"); ////LoadSP(gryImgtmp2, PictureBoxSizeMode.AutoSize, "原垂直精确定位车牌:"); //int[] PH_Last1; //GetHPoj(R3tmp, out PH_Last1); /////*再边缘检测*/ ////PlateE2.GrayImg RLast1tmp; ////int[] TemplateArr3 = new int[9] { 1, 2, 1, 0, 0, 0, -1, -2, -1 }; ////Diptool.Template(out RLast1tmp, R3tmp, TemplateArr3, 3, 1); ////int[] PH_Last2; ////Plttool.GetHPoj(RLast1tmp, out PH_Last2); ////PlateE2.GrayImg[] Chars; ////Plttool.AccurateGetXLP2(PH_Last1, PH_Last2, R3tmp, out Chars); //GrayImg[] Chars; //GrayImg[] Chars1; //将车牌放大至标准 Process.Zoomup(out R3tmp, R3tmp, 200, 40); Process.Zoomup(out R2tmp, R2tmp, 200, 40); //Invert(out R3tmp, R3tmp); AccurateGetXLP3(R3tmp, out Chars); return Chars; }
/// <summary> /// 生成水平投影 /// </summary> /// <param name="psi">待投影灰度图</param> /// <param name="PW">投影数组</param> /// public static void GetWPojY(GrayImg psi, out int[] PW, out int MaxValue) { MaxValue = 0; int Width = psi.Width; int Height = psi.Height; PW = new int[Height]; for (int y = 0; y < Height; y++) { for (int x = 0; x < Width; x++) { PW[y] += psi.Img[y * Width + x]; if (PW[y] > MaxValue) MaxValue = PW[y]; } } MaxValue /= 255; for (int i = 0; i < Height; i++) PW[i] /= 255; return; }
/// <summary> /// 小波列变换 /// </summary> /// <param name="PicMap"></param> public void Transline(GrayImg PicMap) { int i, j, Wide, Height; Wide = PicMap.Width; Height = PicMap.Height; //分配临时空间 byte[] temp = new byte[Wide * Height]; int nHeight = Height / 2; for (i = 0; i < Wide; i++) { for (j = 0; j < nHeight - 1; j++) { int h = j * 2; temp[j * Wide + i] = PicMap.Img[h * Wide + i]; temp[(nHeight + j) * Wide + i] = PicMap.Img[(h + 1) * Wide + i]; } } //通过图像差分,完成小波变换 for (i = 0; i < Wide; i++) { for (j = 0; j < nHeight - 1; j++) { temp[j * Wide + i] = (byte)(temp[(nHeight + j) * Wide + i] - temp[j * Wide + i] + 128); } } //小波经过处理后,入入显示缓存中 for (j = 0; j < Height; j++) { for (i = 0; i < Wide; i++) { PicMap.Img[j * Wide + i] = temp[j * Wide + i]; } } }
/// <summary> /// n层小波变换 /// </summary> /// <param name="PicMap">传入图像</param> /// <param name="n">小波变换层数</param> public void WaveOnce(GrayImg PicMap, int n) { int i, j, Wide, Height, nWide, nHeight; for (int k = 1; k <= n; k++) { //获取传入图像大小 Wide = PicMap.Width; Height = PicMap.Height; //临时数据空间 byte[] temp1 = new byte[Wide * Height]; byte[] temp2 = new byte[Wide * Height]; nWide = (int)(Wide / Math.Pow(2, k)); nHeight = (int)(Height / Math.Pow(2, k)); //完成行变换 for (j = (int)(Height * (1 - 1 / Math.Pow(2, (k - 1)))); j < Height; j++) { for (i = 0; i < nWide; i++) { int w = i * 2; temp1[j * Wide + i] = PicMap.Img[j * Wide + w]; //偶 temp1[j * Wide + nWide + i] = PicMap.Img[j * Wide + w + 1]; //奇 } } //通过图像的差分,完成小波变换 for (j = (int)(Height * (1 - 1 / Math.Pow(2, (k - 1)))); j < Height; j++) { for (i = 0; i < nWide - 1; i++) { temp1[j * Wide + nWide - 1 + i] = (byte)(temp1[j * Wide + nWide - 1 + i] - temp1[j * Wide + i] + 128); } } //完成列变换 for (i = 0; i < Wide / Math.Pow(2, k - 1); i++) { for (j = (int)(Height * (1 - 1 / Math.Pow(2, (k - 1)))); j < Height * (1 - 1 / Math.Pow(2, (k - 1))) + nHeight; j++) { int m, h; m = (int)(Height * (1 - 1 / Math.Pow(2, (k - 1)))); h = (j - m) * 2; temp2[j * Wide + i] = temp1[(m + h) * Wide + i]; //奇数行 temp2[(nHeight + j) * Wide + i] = temp1[(m + h + 1) * Wide + i]; //偶数行 } } //通过图像养分,完成小波变换 for (i = 0; i < Wide / Math.Pow(2, k - 1); i++) { for (j = (int)(Height * (1 - 1 / Math.Pow(2, (k - 1)))); j < Height * (1 - 1 / Math.Pow(2, (k - 1))) + nHeight; j++) { temp2[j * Wide + i] = (byte)(temp2[j * Wide + i] - temp2[(nHeight + j) * Wide + i] + 128); } } //小波经过处理后,放入显示缓存中 for (j = (int)(Height * (1 - 1 / Math.Pow(2, (k - 1)))); j < Height; j++) { for (i = 0; i < Wide / Math.Pow(2, k - 1); i++) { PicMap.Img[j * Wide + i] = temp2[j * Wide + i]; } } } }
/// <summary> /// 拉普拉斯列 /// </summary> public void LapLasRow(GrayImg PicMap) { int i, j, Wide, Height; Wide = PicMap.Width; Height = PicMap.Height; //分配临时空间 byte[] temp1 = new byte[Wide * Height]; for (j = 1; j < Height - 1; j++) { for (i = 1; i < Wide; i++) { //int w = i * 2; //temp1[j * Wide + i] = PicMap.Img[j * Wide + w]; temp1[j * Wide + i] = (byte)(Math.Abs(PicMap.Img[j * Wide + i] * 2 - PicMap.Img[(j - 1) * Wide + i] - PicMap.Img[(j + 1) * Wide + i])); } } for (i = 0; i < Wide * Height; i++) //PicMap.Img[i] = temp1[i]; if (temp1[i] > 10) PicMap.Img[i] = 255; else PicMap.Img[i] = 0; }
/// <summary> /// Hough变换进行车牌校正 /// </summary> /// public int HoughTrans(ref PAngle pAngle, GrayImg pSrcImg, string PrjType) { int i, j, p, o, Max, Tempo; int[] H; int HWidth, HHeight; double temp; o = -90; p = 0; HHeight = 4 * pSrcImg.Width + 1; HWidth = 181; H = new int[HWidth * HHeight]; for (i = -(HHeight / 2); i <= (HHeight / 2); i++) for (j = -(HWidth / 2); j <= (HWidth / 2); j++) H[(i + HHeight / 2) * HWidth + j + HWidth / 2] = 0; switch (PrjType) { case "TPrjType.H_FILTER": for (i = 0; i < pSrcImg.Height; i++) for (j = 0; j < pSrcImg.Width; j++) { if (pSrcImg.Img[i * pSrcImg.Width + j] == 255) { for (o = -10; o <= 10; o++) { if (o >= 0) Tempo = o + 80; else Tempo = o - 80; temp = j * Math.Cos(Tempo * Math.PI / 180.0f) + i * Math.Sin(Tempo * Math.PI / 180.0f); if (temp < 0.0) p = (int)(temp - 0.5); else p = (int)(temp + 0.5); if ((p + HHeight / 2 >= 0) && (p + HHeight / 2 < HHeight)) H[(p + HHeight / 2) * HWidth + Tempo + HWidth / 2]++; } } } Max = 0; for (i = -HHeight / 2; i <= HHeight / 2; i++) for (j = -10; j <= 10; j++) { if (j >= 0) Tempo = j + 80; else Tempo = j - 80; if (Max < H[(i + HHeight / 2) * HWidth + Tempo + HWidth / 2]) { Max = H[(i + HHeight / 2) * HWidth + Tempo + HWidth / 2]; o = Tempo; p = i; } } pAngle.HAngle = o; break; case "TPrjType.V_FILTER": for (i = 0; i < pSrcImg.Height; i++) for (j = 0; j < pSrcImg.Width; j++) { if (pSrcImg.Img[i * pSrcImg.Width + j] == 255) { for (o = -10; o <= 10; o++) { temp = j * Math.Cos(o * Math.PI / 180.0f) + i * Math.Sin(o * Math.PI / 180.0f); if (temp < 0.0) p = (int)(temp - 0.5); else p = (int)(temp + 0.5); if ((p + HHeight / 2 >= 0) && (p + HHeight / 2 < HHeight)) H[(p + HHeight / 2) * HWidth + o + HWidth / 2]++; } } } Max = 0; for (i = -HHeight / 2; i <= HHeight / 2; i++) for (j = -10; j <= 10; j++) { if (Max < H[(i + HHeight / 2) * HWidth + j + HWidth / 2]) { Max = H[(i + HHeight / 2) * HWidth + j + HWidth / 2]; o = j; p = i; } } pAngle.VAngle = o; break; default: return 0; } return 1; }
/// <summary> /// 倾斜度校正(新增) /// </summary> /// <param name="pDestImg"></param> /// <param name="pSrcImg"></param> /// <param name="Angle"></param> public void RectifyLP_2(out GrayImg pDestImg, GrayImg pSrcImg, PAngle Angle) { int i, j; double RectifyAngle = 0; ; int iAngle; GrayImg TempImg1, TempImg2; PicBase.ImgMalloc(out TempImg1, pSrcImg.Width, pSrcImg.Height); if (Math.Abs(Angle.HAngle + 90) != 90.0) RectifyAngle = -(Angle.HAngle + 90.0) / 180.0f * Math.PI; for (i = 0; i < pSrcImg.Width; i++) for (j = 0; j < pSrcImg.Height; j++) { if (i * Math.Tan(RectifyAngle) < 0.0) iAngle = (int)(i * Math.Tan(RectifyAngle) - 0.5); else iAngle = (int)(i * Math.Tan(RectifyAngle) + 0.5); if ((j - iAngle >= 0) && (j - iAngle < pSrcImg.Height)) { TempImg1.Img[j * TempImg1.Width + i] = pSrcImg.Img[(j - iAngle) * pSrcImg.Width + i]; } } PicBase.ImgMalloc(out TempImg2, pSrcImg.Width, pSrcImg.Height); if (Math.Abs(Angle.VAngle) != 90.0) RectifyAngle = Angle.VAngle / 180.0f * Math.PI; for (i = 0; i < TempImg1.Height; i++) for (j = 0; j < TempImg1.Width; j++) { if (i * Math.Tan(RectifyAngle) < 0.0) iAngle = (int)(i * Math.Tan(RectifyAngle) - 0.5); else iAngle = (int)(i * Math.Tan(RectifyAngle) + 0.5); if ((j - iAngle >= 0) && (j - iAngle < TempImg1.Width)) { TempImg2.Img[i * TempImg2.Width + j] = TempImg1.Img[i * TempImg1.Width + j - iAngle]; } } pDestImg.Width = TempImg2.Width; pDestImg.Height = TempImg2.Height; pDestImg.Img = TempImg2.Img; }
/// <summary> /// 车牌校正 /// </summary> public void RectifyLP(out GrayImg pDestImg, GrayImg pSrcImg, GrayImg pModelImg, ref PAngle Angle) { pDestImg = new GrayImg(); GrayImg RowDiffImg; Diff(out RowDiffImg, pModelImg, "TPrjType.H_FILTER"); HoughTrans(ref Angle, RowDiffImg, "TPrjType.V_FILTER"); Diff(out RowDiffImg, pModelImg, "TPrjType.V_FILTER"); HoughTrans(ref Angle, RowDiffImg, "TPrjType.H_FILTER"); RectifyLP_2(out pDestImg, pSrcImg, Angle); }
/// <summary> /// 查找车牌中第一个字符 /// </summary> /// <param name="pDestImg">处理后车牌图像</param> /// <param name="pSrcImg">传入车牌区域图像</param> /// <param name="PCombine">综合投影数组</param> /// <param name="pGryImg"></param> public void LocVPlateLeft(out GrayImg pDestImg, GrayImg pSrcImg, int[] PCombine, ref GrayImg pGryImg) { //搜索波形 ArrayList StartX = new ArrayList(); ArrayList EndX = new ArrayList(); bool Flag = false; for (int i = 0; i < PCombine.Length; i++) { if (PCombine[i] != 0 && !Flag) { StartX.Add(i); Flag = true; } else if (PCombine[i] == 0 && Flag) { EndX.Add(i); Flag = false; } if (i == PCombine.Length - 1 && Flag) { EndX.Add(i); Flag = false; } } /*预估计车牌文字的最小宽度首部字母12,尾部字母为8*/ for (int i = StartX.Count - 1; i >= 0; i--) { int wlen = (int)EndX[i] - (int)StartX[i]; if (wlen < 4 && i <= 2) //除掉此波形 { StartX.RemoveAt(i); EndX.RemoveAt(i); } if (wlen < 3 && i > 2) //除掉此波形 { StartX.RemoveAt(i); EndX.RemoveAt(i); } } int sx = 0; int ex = PCombine.Length - 1; if (StartX.Count > 0) { sx = (int)StartX[0]; ex = (int)EndX[EndX.Count - 1]; } //CutImg(out pDestImg, pSrcImg, sx, ex, 0, pSrcImg.Height - 1); //CutImg(out pGryImg, pGryImg, sx, ex, 0, pSrcImg.Height - 1); Process.GetSubImg(out pDestImg, pSrcImg, new Rectangle(sx, 0, ex - sx, pSrcImg.Height)); Process.GetSubImg(out pGryImg, pGryImg, new Rectangle(sx, 0, ex - sx, pSrcImg.Height)); }
/// <summary> /// 低通滤波 /// </summary> /// <param name="PicMap">传入图像</param> /// <param name="n">滤波次数</param> public void LowFilter(GrayImg PicMap, int n) { int i, j, Width, Height, nWidth, nHeight; Width = PicMap.Width; Height = PicMap.Height; nWidth = Width / 2; nHeight = Height / 2; WaveOnce(PicMap, n); for (j = 0; j < Height; j++) { for (i = 0; i < Width; i++) { if ((j >= Height * (1 - 1 / Math.Pow(2, (n - 1)))) && (i < Width / Math.Pow(2, n))) continue; else PicMap.Img[j * Width + i] = (byte)128; } } IDWT(PicMap, n); }
/// <summary> /// 使用Canny算子处理结果切割车牌区域 /// </summary> /// <param name="pltImg1"></param> /// <param name="result"></param> public static GrayImg[] CutCharByCanny(GrayImg pltImg1, GrayImg result) { //将车牌区域放大至200*80 Process.Zoomup(out result, result, 200, 80); Process.Zoomup(out pltImg1, pltImg1, 200, 80); //LoadSP(result, PictureBoxSizeMode.Normal, "放大"); //LoadSP(pltImg1, PictureBoxSizeMode.Normal, "放大"); ////对车牌区域水平变化率进行投影 //Pictool.TransY(result, out width, out Height); //Pictool.GenWProjImgY(out result, width, Height); //LoadSP(result, PictureBoxSizeMode.Normal, "水平变化率投影"); //投影所需参数 int[] width; int Height; //对Canny算子处理结果(车牌区域)进行垂直投影 Process.GetWPojX(result, out width, out Height); Process.GenWProjImgX(out result, width, Height); //diptool.Invert(out pltImg1, pltImg1); //Pictool.GetWPojX(pltImg1, out width, out Height); //Pictool.GenWProjImgX(out pltImg1, width, Height); //LoadSP(result, PictureBoxSizeMode.Normal, "垂直投影"); ////二值化 int t2 = Process.BinaryImg(pltImg1); Process.BinaryImg(pltImg1,out pltImg1, t2); //diptool.Zoomup(out pltImg1, pltImg1, 200, 40); //LoadSP(pltImg1, PictureBoxSizeMode.Normal, "二值化"); //LoadSP(pltImg1, PictureBoxSizeMode.Normal, "原始"); //对车牌区域进行闭运算 //Closing(out pltImg1, pltImg1); ////Pictool.Dilation_8(pltImg1,out pltImg1); //LoadSP(pltImg1, PictureBoxSizeMode.Normal, "闭运算"); GrayImg[] Chars; //固定卡位法切割 ////Pictool.AccurateGetXLP3(width, pltImg1, out Chars); ////for (int i = 0; i < 7; i++) ////{ //// //diptool.GetSubImg(out Chars[i], pltImg1, new Rectangle(CharsRegion[i].Start, 0, CharLength[i], 80)); //// LoadSP(Chars[i], PictureBoxSizeMode.Normal, "切割后字符"); ////} //使用Canny算子处理结算进行字符切割 extent[] CharsRegion; CutChar(result, out CharsRegion, width); if (CharsRegion.Length < 7) Chars = new GrayImg[10]; else Chars = new GrayImg[CharsRegion.Length + 3]; //计算每个可能字符区域的宽度 int[] CharLength = new int[CharsRegion.Length]; for (int temp = 0; temp < CharsRegion.Length; temp++) CharLength[temp] = CharsRegion[temp].End - CharsRegion[temp].Start; int curr = 0; for (int i = 0; i < CharsRegion.Length; i++) { if (CharLength[i] > 110) { Process.GetSubImg(out Chars[curr], pltImg1, new Rectangle(CharsRegion[i].Start, 0, CharLength[i] / 5, pltImg1.Height)); //Pictool.Closing(out Chars[i], Chars[i]); //LoadSP(Chars[curr], PictureBoxSizeMode.Normal, "切割后字符"); curr++; Process.GetSubImg(out Chars[curr], pltImg1, new Rectangle(CharsRegion[i].Start + CharLength[i] / 5, 0, CharLength[i] / 5, pltImg1.Height)); //Pictool.Closing(out Chars[i], Chars[i]); //LoadSP(Chars[curr], PictureBoxSizeMode.Normal, "切割后字符"); curr++; Process.GetSubImg(out Chars[curr], pltImg1, new Rectangle(CharsRegion[i].Start + 2 * CharLength[i] / 5, 0, CharLength[i] / 5, pltImg1.Height)); //Pictool.Closing(out Chars[i], Chars[i]); //LoadSP(Chars[curr], PictureBoxSizeMode.Normal, "切割后字符"); curr++; Process.GetSubImg(out Chars[curr], pltImg1, new Rectangle(CharsRegion[i].Start + 3 * CharLength[i] / 5, 0, CharLength[i] / 5, pltImg1.Height)); //Pictool.Closing(out Chars[i], Chars[i]); //LoadSP(Chars[curr], PictureBoxSizeMode.Normal, "切割后字符"); curr++; Process.GetSubImg(out Chars[curr], pltImg1, new Rectangle(CharsRegion[i].Start + 4 * CharLength[i] / 5, 0, CharLength[i] / 5, pltImg1.Height)); //Pictool.Closing(out Chars[i], Chars[i]); //LoadSP(Chars[curr], PictureBoxSizeMode.Normal, "切割后字符"); curr++; } else if (CharLength[i] > 85) { Process.GetSubImg(out Chars[curr], pltImg1, new Rectangle(CharsRegion[i].Start, 0, CharLength[i] / 4, pltImg1.Height)); //Pictool.Closing(out Chars[i], Chars[i]); //LoadSP(Chars[curr], PictureBoxSizeMode.Normal, "切割后字符"); curr++; Process.GetSubImg(out Chars[curr], pltImg1, new Rectangle(CharsRegion[i].Start + CharLength[i] / 3, 0, CharLength[i] / 3, pltImg1.Height)); //Pictool.Closing(out Chars[i], Chars[i]); //LoadSP(Chars[curr], PictureBoxSizeMode.Normal, "切割后字符"); curr++; Process.GetSubImg(out Chars[curr], pltImg1, new Rectangle(CharsRegion[i].Start + 2 * CharLength[i] / 4, 0, CharLength[i] / 4, pltImg1.Height)); //Pictool.Closing(out Chars[i], Chars[i]); //LoadSP(Chars[curr], PictureBoxSizeMode.Normal, "切割后字符"); curr++; Process.GetSubImg(out Chars[curr], pltImg1, new Rectangle(CharsRegion[i].Start + 3 * CharLength[i] / 4, 0, CharLength[i] / 4, pltImg1.Height)); //Pictool.Closing(out Chars[i], Chars[i]); //LoadSP(Chars[curr], PictureBoxSizeMode.Normal, "切割后字符"); curr++; } else if (CharLength[i] > 65) { Process.GetSubImg(out Chars[curr], pltImg1, new Rectangle(CharsRegion[i].Start, 0, CharLength[i] / 3, pltImg1.Height)); //Pictool.Closing(out Chars[i], Chars[i]); //LoadSP(Chars[curr], PictureBoxSizeMode.Normal, "切割后字符"); curr++; Process.GetSubImg(out Chars[curr], pltImg1, new Rectangle(CharsRegion[i].Start + CharLength[i] / 3, 0, CharLength[i] / 3, pltImg1.Height)); //Pictool.Closing(out Chars[i], Chars[i]); //LoadSP(Chars[curr], PictureBoxSizeMode.Normal, "切割后字符"); curr++; Process.GetSubImg(out Chars[curr], pltImg1, new Rectangle(CharsRegion[i].Start + 2 * CharLength[i] / 3, 0, CharLength[i] / 3, pltImg1.Height)); //Pictool.Closing(out Chars[i], Chars[i]); //LoadSP(Chars[curr], PictureBoxSizeMode.Normal, "切割后字符"); curr++; } else if (CharLength[i] > 35) { Process.GetSubImg(out Chars[curr], pltImg1, new Rectangle(CharsRegion[i].Start, 0, CharLength[i] / 2, pltImg1.Height)); //Pictool.Closing(out Chars[i], Chars[i]); //LoadSP(Chars[curr], PictureBoxSizeMode.Normal, "切割后字符"); curr++; Process.GetSubImg(out Chars[curr], pltImg1, new Rectangle(CharsRegion[i].Start + CharLength[i] / 2, 0, CharLength[i] / 2, pltImg1.Height)); //Pictool.Closing(out Chars[i], Chars[i]); //LoadSP(Chars[curr], PictureBoxSizeMode.Normal, "切割后字符"); curr++; } else if (CharLength[i] > 0) { Process.GetSubImg(out Chars[curr], pltImg1, new Rectangle(CharsRegion[i].Start, 0, CharLength[i], pltImg1.Height)); //Pictool.Closing(out Chars[i], Chars[i]); //LoadSP(Chars[curr], PictureBoxSizeMode.Normal, "切割后字符"); curr++; } } return Chars; //////int curr = 0; ////////目前区域和下一个波形区域均不能构成一个字符 //////while ((CharLength[i]+CharLength[i+1]< 18) && (i < (CharsRegion.Length - 1))) //////{ ////// i++; //////} ////////目前区域能构成一个字符 //////if (CharLength[i] > 18 && (i < (CharsRegion.Length - 1))) //////{ ////// diptool.GetSubImg(out Chars[curr], pltImg1, new Rectangle(CharsRegion[i].Start, 0, CharLength[i], 80)); ////// LoadSP(Chars[curr], PictureBoxSizeMode.Normal, "切割后字符"); ////// i++; ////// curr++; //////} ////////目前区域和下一个波形区域能构成一个字符 //////else if (CharLength[i] + CharLength[i + 1] > 18 && CharLength[i] + CharLength[i + 1] < 36 && (i < (CharsRegion.Length - 1))) //////{ ////// diptool.GetSubImg(out Chars[curr], pltImg1, new Rectangle(CharsRegion[i].Start, 0, CharLength[i] + CharLength[i + 1], 80)); ////// LoadSP(Chars[curr], PictureBoxSizeMode.Normal, "切割后字符"); ////// i += 2; ////// curr++; //////} //////else ////// i++; ////////目前区域能构成一个字符 //////if (CharLength[i] > 18 && (i < (CharsRegion.Length - 1))) //////{ ////// diptool.GetSubImg(out Chars[curr], pltImg1, new Rectangle(CharsRegion[i].Start, 0, CharLength[i], 80)); ////// LoadSP(Chars[curr], PictureBoxSizeMode.Normal, "切割后字符"); ////// i++; ////// curr++; //////} ////////目前区域和下一个波形区域能构成一个字符 //////else if (CharLength[i] + CharLength[i + 1] > 18 && CharLength[i] + CharLength[i + 1] < 30 && (i < (CharsRegion.Length - 1))) //////{ ////// diptool.GetSubImg(out Chars[curr], pltImg1, new Rectangle(CharsRegion[i].Start, 0, CharLength[i] + CharLength[i + 1], 80)); ////// LoadSP(Chars[curr], PictureBoxSizeMode.Normal, "切割后字符"); ////// i += 2; ////// curr++; //////} //////while (curr < 7) //////{ ////// if (CharsRegion[i].End - CharsRegion[i].Start > 30) ////// { ////// diptool.GetSubImg(out Chars[curr], pltImg1, new Rectangle(CharsRegion[i].Start, 0, (CharsRegion[i].End - CharsRegion[i].Start) / 2, 80)); ////// LoadSP(Chars[curr], PictureBoxSizeMode.Normal, "切割后字符"); ////// curr++; ////// diptool.GetSubImg(out Chars[curr], pltImg1, new Rectangle(CharsRegion[i].Start + (CharsRegion[i].End - CharsRegion[i].Start) / 2, 0, (CharsRegion[i].End - CharsRegion[i].Start) / 2, 80)); ////// LoadSP(Chars[curr], PictureBoxSizeMode.Normal, "切割后字符"); ////// } ////// else ////// { ////// diptool.GetSubImg(out Chars[curr], pltImg1, new Rectangle(CharsRegion[i].Start, 0, CharsRegion[i].End - CharsRegion[i].Start, 80)); ////// LoadSP(Chars[curr], PictureBoxSizeMode.Normal, "切割后字符"); ////// curr++; ////// } ////// i++; //////} //PlateE2.GrayImg[] Chars; //PlateE2.GrayImg[] Chars1; //Plttool.AccurateGetXLP3(PHCombine, R3tmp, out Chars1, gryImgtmp2, out Chars); }
/// <summary> /// 小波行变换 /// </summary> public void TransRow(GrayImg PicMap) { int i, j, Wide, Height; Wide = PicMap.Width; Height = PicMap.Height; //分配临时空间 byte[] temp1 = new byte[Wide * Height]; int nWide = Wide / 2; for (j = 0; j < Height; j++) { for (i = 0; i < nWide; i++) { int w = i * 2; temp1[j * Wide + i] = PicMap.Img[j * Wide + w]; temp1[j * Wide + nWide + i] = PicMap.Img[j * Wide + w + 1]; } } //通过图像差分,完成小波变换 for (j = 0; j < Height; j++) { for (i = 0; i < nWide - 1; i++) { temp1[j * Wide + nWide - 1 + i] = (byte)(temp1[j * Wide + (nWide - 1) + i] - temp1[j * Wide + i] + 128); } } //小波经过处理后,入入显示缓存中 for (j = 0; j < Height; j++) { for (i = 0; i < Wide; i++) { PicMap.Img[j * Wide + i] = temp1[j * Wide + i]; } } }
/// <summary> /// 固定卡出字符区域 /// </summary> /// <param name="PCombine">投影数组</param> /// <param name="pSrcImg">待切割图像</param> /// <param name="pDestImgs">切割后图像</param> /// <param name="pGrayImg"></param> /// <param name="outchargry"></param> public void AccurateGetXLP3(GrayImg pSrcImg, out GrayImg[] pDestImgs/*, GrayImg pGrayImg, out GrayImg[] outchargry*/) { pDestImgs = new GrayImg[7]; int Height = pSrcImg.Height; /*统计*/ int[] PH; Process.GetHPoj(pSrcImg, out PH); //int cut1 = 18, cut2 = 50, cut3 = 85, cut4 = 115, cut5 = 125, cut6 = 165; int[] cut = { 25, 48, 85, 115, 135, 155 }; // int[] cutd = { 35, 66, 95, 125, 145, 175 }; // for (int i = 0; i < 6; i++) { int low = PH[cut[i]]; for (int c = cut[i]; c <= cutd[i]; c++) { if (PH[c] < low) { low = PH[c]; cut[i] = c; } } } //CutImg(out pDestImgs[0], pSrcImg, 0, cut[0], 1, 39); //CutImg(out pDestImgs[1], pSrcImg, cut[0], cut[1], 1, 39); //CutImg(out pDestImgs[2], pSrcImg, cut[1], cut[2], 1, 39); //CutImg(out pDestImgs[3], pSrcImg, cut[2], cut[3], 1, 39); //CutImg(out pDestImgs[4], pSrcImg, cut[3], cut[4], 1, 39); //CutImg(out pDestImgs[5], pSrcImg, cut[4], cut[5], 1, 39); //CutImg(out pDestImgs[6], pSrcImg, cut[5], 196, 1, 39); Process.GetSubImg(out pDestImgs[0], pSrcImg, new Rectangle(0, 0, cut[0], Height)); Process.GetSubImg(out pDestImgs[1], pSrcImg, new Rectangle(cut[0], 0, cut[1] - cut[0], Height)); Process.GetSubImg(out pDestImgs[2], pSrcImg, new Rectangle(cut[1], 0, cut[2] - cut[1], Height)); Process.GetSubImg(out pDestImgs[3], pSrcImg, new Rectangle(cut[2], 0, cut[3] - cut[2], Height)); Process.GetSubImg(out pDestImgs[4], pSrcImg, new Rectangle(cut[3], 0, cut[4] - cut[3], Height)); Process.GetSubImg(out pDestImgs[5], pSrcImg, new Rectangle(cut[4], 0, cut[5] - cut[4], Height)); Process.GetSubImg(out pDestImgs[6], pSrcImg, new Rectangle(cut[5], 0, pSrcImg.Width - 1 - cut[5], Height)); //GetSubImg(out pDestImgs[1], pSrcImg, new Rectangle(cut[0], 0, cut[1] - cut[0], Height)); //outchargry = new GrayImg[7]; //CutImg(out outchargry[0], pGrayImg, 0, cut[0], 1, 39); //CutImg(out outchargry[1], pGrayImg, cut[0], cut[1], 1, 39); //CutImg(out outchargry[2], pGrayImg, cut[1], cut[2], 1, 39); //CutImg(out outchargry[3], pGrayImg, cut[2], cut[3], 1, 39); //CutImg(out outchargry[4], pGrayImg, cut[3], cut[4], 1, 39); //CutImg(out outchargry[5], pGrayImg, cut[4], cut[5], 1, 39); //CutImg(out outchargry[6], pGrayImg, cut[5], 196, 1, 39); }
/// <summary> /// n层小波逆变换 /// </summary> /// <param name="PicMap">传入图像</param> /// <param name="n">变换次数</param> public void IDWT(GrayImg PicMap, int n) { int i, j, Width, Height, nWide, nHeight; for (int k = n; k >= 1; k--) { //获取图像大小 Width = PicMap.Width; Height = PicMap.Height; //分配临时存储空间 byte[] temp1 = new byte[Width * Height]; byte[] temp2 = new byte[Width * Height]; byte[] temp3 = new byte[Width * Height]; nWide = (int)(Width / Math.Pow(2, k)); nHeight = (int)(Height / Math.Pow(2, k)); //内存复制 PicMap.Img.CopyTo(temp1, 0); //bool result = temp1.Equals(PicMap.Img); for (i = 0; i < Width / Math.Pow(2, k - 1); i++) { for (j = (int)(Height * (1 - 1 / Math.Pow(2, (k - 1)))); j < Height * (1 - 1 / Math.Pow(2, (k - 1))) + nHeight; j++) { temp1[j * Width + i] = (byte)(temp1[(nHeight + j) * Width + i] + temp1[j * Width + i] - 128); } } for (i = 0; i < Width / Math.Pow(2, k - 1); i++) { for (j = (int)(Height * (1 - 1 / Math.Pow(2, (k - 1)))); j < Height * (1 - 1 / Math.Pow(2, (k - 1))) + nHeight; j++) { int m, h; m = (int)(Height * (1 - 1 / Math.Pow(2, (k - 1)))); h = (j - m) * 2; temp2[(m + h) * Width + i] = temp1[j * Width + i]; temp2[(m + h + 1) * Width + i] = temp1[(nHeight + j) * Width + i]; } } for (j = (int)(Height * (1 - 1 / Math.Pow(2, (k - 1)))); j < Height; j++) { for (i = 0; i < nWide - 1; i++) { temp2[j * Width + nWide + i] += (byte)(temp2[j * Width + i] - 128); } } for (j = (int)(Height * (1 - 1 / Math.Pow(2, (k - 1)))); j < Height; j++) { for (i = 0; i < nWide; i++) { int w = i * 2; temp3[j * Width + w] = temp2[j * Width + i]; temp3[j * Width + w + 1] = temp2[j * Width + nWide + i]; } } //逆变换后,放入显示缓存中 for (j = (int)(Height * (1 - 1 / Math.Pow(2, (k - 1)))); j < Height; j++) { for (i = 0; i < Width / Math.Pow(2, k - 1); i++) { PicMap.Img[j * Width + i] = (byte)(temp3[j * Width + i]); } } } }
public int Diff(out GrayImg pDestImg, GrayImg pSrcImg, string PrjType) { pDestImg = new GrayImg(); int i, j; int Temp; GrayImg TempImg; PicBase.ImgMalloc(out TempImg, pSrcImg.Width, pSrcImg.Height); switch (PrjType) { case "TPrjType.H_FILTER": for (i = 0; i < pSrcImg.Height; i++) TempImg.Img[i * TempImg.Width] = 0; for (i = 0; i < pSrcImg.Height; i++) for (j = 1; j < pSrcImg.Width; j++) { Temp = Math.Abs(pSrcImg.Img[i * pSrcImg.Width + j] - pSrcImg.Img[i * pSrcImg.Width + j - 1]); if (Temp > 80) Temp = 255; else Temp = 0; TempImg.Img[i * TempImg.Width + j] = (byte)Temp; } break; case "TPrjType.V_FILTER": for (j = 0; j < pSrcImg.Width; j++) TempImg.Img[j] = 0; for (j = 0; j < pSrcImg.Width; j++) for (i = 1; i < pSrcImg.Height; i++) { Temp = Math.Abs(pSrcImg.Img[i * pSrcImg.Width + j] - pSrcImg.Img[(i - 1) * pSrcImg.Width + j]); if (Temp > 80) Temp = 255; else Temp = 0; TempImg.Img[i * TempImg.Width + j] = (byte)Temp; } break; default: return 0; } pDestImg.Width = TempImg.Width; pDestImg.Height = TempImg.Height; pDestImg.Img = TempImg.Img; return 1; }
/// <summary> /// 生成车牌水平投影 /// </summary> /// <param name="pHProject"></param> /// <param name="pSrcImg"></param> /// <param name="FilterTH"></param> private void HProjectImg(ref int[] pHProject, GrayImg pSrcImg, int FilterTH) { //获取投影 for (int i = 0; i < pSrcImg.Height; i++) { for (int j = 0; j < pSrcImg.Width; j++) { if (pSrcImg.Img[i * pSrcImg.Width + j] == 255) pHProject[i]++; } } //投影过滤 for (int i = 0; i < pSrcImg.Height; i++) { if (pHProject[i] < FilterTH) pHProject[i] = 0; } bool Flag1 = true; int Temp = 0; for (int i = 0; i < pSrcImg.Height; i++) { int avg = 0; if (pHProject[i] != 0 && Flag1) { Temp = i; Flag1 = false; } if (pHProject[i] == 0 && (!Flag1)) { for (int j = Temp; j <= i; j++) avg = avg + pHProject[j]; avg = avg / (i - Temp); if ((i - Temp < (int)(PltHMin * 0.35f + 0.5)) || (avg < (int)(PltHMax * 0.3f + 0.5f))) { for (int j = Temp; j < i; j++) pHProject[j] = 0; } Flag1 = true; } } }