/// <summary> /// 注目画素の周辺画素の最大値と最小値を求める /// </summary> /// <param name="img">画像の画素データ</param> /// <param name="x">x座標</param> /// <param name="y">y座標</param> /// <param name="size">周辺画素の探索サイズ。奇数でなければならない</param> /// <param name="min">出力される最小値</param> /// <param name="max">出力される最大値</param> private static void MinMax(Mat img, int x, int y, int size, out byte min, out byte max) { int size2 = size / 2; min = byte.MaxValue; max = byte.MinValue; int xs = Math.Max(x - size2, 0); int xe = Math.Min(x + size2, img.Width); int ys = Math.Max(y - size2, 0); int ye = Math.Min(y + size2, img.Height); using (var tImg = new MatOfByte(img)) { var indexer = tImg.GetIndexer(); for (int xx = xs; xx < xe; xx++) { for (int yy = ys; yy < ye; yy++) { byte v = indexer[yy, xx]; if (max < v) { max = v; } else if (min > v) { min = v; } } } } }
static Mat doKernel(Mat img, Mat kernel) { Mat outputImg = new Mat(); int kernel_size = kernel.Cols; int pad = (kernel_size - 1) / 2; img.CopyTo(outputImg); MatOfByte mat = new MatOfByte(outputImg); var idx = mat.GetIndexer(); MatOfByte kernel_mat = new MatOfByte(kernel); var kernel_idx = kernel_mat.GetIndexer(); Console.WriteLine(kernel_mat.ToCvMat()); for (int k_row = 0; k_row < kernel_size; k_row++) // k - kernel { for (int k_col = 0; k_col < kernel_size; k_col++) { Console.WriteLine(kernel_idx[k_row, k_col]); } } float sum = 0; for (int c_row = pad; c_row < mat.Rows; c_row++) // c- center { for (int c_col = pad; c_col < mat.Cols - pad; c_col++) { sum = 0; for (int k_row = 0; k_row < kernel_size; k_row++) // k - kernel { for (int k_col = 0; k_col < kernel_size; k_col++) { sum += idx[c_row - pad + k_row, c_col - pad + k_col] * kernel_idx[k_row, k_col] * 1 / (kernel_size * kernel_size); var testShit = idx[c_row - pad + k_row, c_col - pad + k_col].ToString(); var testKernel = kernel_idx[k_row, k_col]; // Console.WriteLine(testShit + " " + testKernel); } } idx[c_row, c_col] = (byte)sum; } } return(outputImg); }
public void MatIndexer() { const byte value = 123; var img = new Mat(new Size(10, 10), MatType.CV_8UC1, Scalar.All(value)); var imgB = new MatOfByte(img); var indexer = imgB.GetIndexer(); var generiCIndexer = img.GetGenericIndexer <byte>(); Assert.Equal(value, indexer[0, 0]); Assert.Equal(value, generiCIndexer[0, 0]); img.Dispose(); imgB.Dispose(); }
private static float[] HistogramCalculations(Mat img) { MatOfByte mat = new MatOfByte(img); var idx = mat.GetIndexer(); float[] histvalue = new float[256]; for (int row = 0; row < img.Rows; row++) { for (int col = 0; col < img.Cols; col++) { histvalue[idx[row, col]]++; } } return(histvalue); }
/// <summary> /// Niblackの手法による二値化処理を行う。 /// </summary> /// <param name="imgSrc">入力画像</param> /// <param name="imgDst">出力画像</param> /// <param name="kernelSize">局所領域のサイズ</param> /// <param name="k">係数</param> #else /// <summary> /// Binarizes by Niblack's method /// </summary> /// <param name="src">Input image</param> /// <param name="dst">Output image</param> /// <param name="kernelSize">Window size</param> /// <param name="k">Adequate coefficient</param> #endif public static void Niblack(Mat src, Mat dst, int kernelSize, double k) { if (src == null) throw new ArgumentNullException("src"); if (dst == null) throw new ArgumentNullException("dst"); // グレースケールのみ if (src.Type() != MatType.CV_8UC1) throw new ArgumentException("src must be gray scale image"); if (dst.Type() != MatType.CV_8UC1) throw new ArgumentException("dst must be gray scale image"); // サイズのチェック if (kernelSize < 3) throw new ArgumentOutOfRangeException("kernelSize", "size must be 3 and above"); if (kernelSize % 2 == 0) throw new ArgumentOutOfRangeException("kernelSize", "size must be odd number"); int width = src.Width; int height = src.Height; dst.Create(src.Size(), src.Type()); using (var tSrcMat = new MatOfByte(src)) using (var tDstMat = new MatOfByte(dst)) { var tSrc = tSrcMat.GetIndexer(); var tDst = tDstMat.GetIndexer(); //for (int y = 0; y < gray.Height; y++) MyParallel.For(0, height, delegate(int y) { for (int x = 0; x < width; x++) { double m, s; MeanStddev(src, x, y, kernelSize, out m, out s); double threshold = m + k * s; if (tSrc[y, x] < threshold) tDst[y, x] = 0; else tDst[y, x] = 255; } } ); } }
public Dictionary <string, BitmapSource> SplitColoredQR(Mat combinedMat) { Dictionary <string, BitmapSource> outputSplitImages = new Dictionary <string, BitmapSource>(); Size size = new Size(combinedMat.Width, combinedMat.Height); int depth = combinedMat.Depth(); Mat redComponent = Mat.Zeros(size, MatType.CV_8UC1); Mat grnComponent = Mat.Zeros(size, MatType.CV_8UC1); Mat bluComponent = Mat.Zeros(size, MatType.CV_8UC1); // Get mat indexers MatOfByte3 mobComb = new MatOfByte3(combinedMat); MatOfByte mobRed = new MatOfByte(redComponent); MatOfByte mobGrn = new MatOfByte(grnComponent); MatOfByte mobBlu = new MatOfByte(bluComponent); MatIndexer <Vec3b> indexerComb = mobComb.GetIndexer(); MatIndexer <byte> indexerRed = mobRed.GetIndexer(); MatIndexer <byte> indexerGrn = mobGrn.GetIndexer(); MatIndexer <byte> indexerBlu = mobBlu.GetIndexer(); for (int y = 0; y < combinedMat.Height; y++) { for (int x = 0; x < combinedMat.Width; x++) { // Assign intensity of red channel from the combined mat to the red component mat indexerRed[y, x] = indexerComb[y, x].Item2; // Assign intensity of green channel from the combined mat to the green component mat indexerGrn[y, x] = indexerComb[y, x].Item1; // Assign intensity of blue channel from the combined mat to the blue component mat indexerBlu[y, x] = indexerComb[y, x].Item0; } } outputSplitImages.Add(QR_TYPE_RED_OUT, Utils.MatToImage(redComponent)); outputSplitImages.Add(QR_TYPE_GREEN_OUT, Utils.MatToImage(grnComponent)); outputSplitImages.Add(QR_TYPE_BLUE_OUT, Utils.MatToImage(bluComponent)); return(outputSplitImages); }
//(practice) static public Mat Displace(this Mat Uimg, int sftX, int sftY, bool DispB) //位置移動 { Size sz = Uimg.Size(); int W = sz.Width, H = sz.Height; Mat UimgD = new Mat(sz, MatType.CV_8UC1, Scalar.All(255)); { using (MatOfByte imgMBS = new MatOfByte(Uimg)) using (MatOfByte imgMBD = new MatOfByte(UimgD)){ var IdxS = imgMBS.GetIndexer(); var IdxD = imgMBD.GetIndexer(); for (int y = 0; y < H; y++) { int yy = y + sftY; if (yy < 0 || yy >= H) { continue; } for (int x = 0; x < W; x++) { int xx = x + sftX; if (xx < 0 || xx >= W - 1) { continue; } IdxD[yy, xx] = IdxS[y, x]; } } } } if (DispB) { // using(new Window("origin",WindowMode.Normal,Uimg)) using (new Window("Displaced", WindowMode.Normal, UimgD)){ Cv2.WaitKey(0); } } return(UimgD); }
static public Mat RandomWhite(this Mat Uimg, double rndP, bool DispB) { Size sz = Uimg.Size(); int W = sz.Width, H = sz.Height, h2 = H / 2; Mat UimgD = Uimg.Clone(); // new Mat(sz,MatType.CV_8UC1,Scalar.All(255)); { using (MatOfByte imgMBS = new MatOfByte(Uimg)) using (MatOfByte imgMBD = new MatOfByte(UimgD)){ var IdxS = imgMBS.GetIndexer(); var IdxD = imgMBD.GetIndexer(); for (int y = 0; y < H; y++) { for (int x = 0; x < W; x++) { if (IdxS[y, x] == 255) { continue; } if (rndRW.NextDouble() < rndP) { IdxD[y, x] = 255; } } } } } if (DispB) { // using(new Window("origin",WindowMode.Normal,Uimg)) using (new Window("RandomWhite", WindowMode.Normal, UimgD)){ Cv2.WaitKey(0); } } return(UimgD); }
/// <summary> /// 注目画素の周辺画素の平均値と標準偏差を求める /// </summary> /// <param name="img">画像の画素データ</param> /// <param name="x">x座標</param> /// <param name="y">y座標</param> /// <param name="size">周辺画素の探索サイズ。奇数でなければならない</param> /// <param name="mean">出力される平均</param> /// <param name="stddev">出力される標準偏差</param> private static void MeanStddev(Mat img, int x, int y, int size, out double mean, out double stddev) { int count = 0; int sum = 0; int sqsum = 0; int size2 = size / 2; int xs = Math.Max(x - size2, 0); int xe = Math.Min(x + size2, img.Width); int ys = Math.Max(y - size2, 0); int ye = Math.Min(y + size2, img.Height); byte v; using (var tImg = new MatOfByte(img)) { var indexer = tImg.GetIndexer(); for (int xx = xs; xx < xe; xx++) { for (int yy = ys; yy < ye; yy++) { v = indexer[yy, xx]; sum += v; sqsum += v * v; count++; } } } mean = (double)sum / count; double var = ((double)sqsum / count) - (mean * mean); if (var < 0.0) { var = 0.0; } stddev = Math.Sqrt(var); }
public bool MaskOutline(Mat whiteLightImage, Mat edgeMaskImage, out Mat mergedImage) { bool result = false; mergedImage = whiteLightImage.Clone(); try { //convert white mask outlines to purple color outlines MatOfByte matb = new MatOfByte(edgeMaskImage); var indexerGray = matb.GetIndexer(); MatOfByte3 mat3 = new MatOfByte3(mergedImage); var indexerColor = mat3.GetIndexer(); for (int y = 0; y < edgeMaskImage.Height; y++) { for (int x = 0; x < edgeMaskImage.Width; x++) { byte edge = indexerGray[y, x]; if (edge == 255) //white { indexerColor[y, x] = new Vec3b(255, 128, 255); //purple } } } result = true; } catch (Exception ex) { } return(result); }
static Mat doMedianFilter(Mat img, Mat kernel) { Mat outputImg = new Mat(); int kernel_size = kernel.Cols; int pad = (kernel_size - 1) / 2; img.CopyTo(outputImg); MatOfByte mat = new MatOfByte(outputImg); var idx = mat.GetIndexer(); int k = 0; decimal[] vector = new decimal[kernel_size * kernel_size]; for (int c_row = pad; c_row < mat.Rows - pad; c_row++) // c- center { for (int c_col = pad; c_col < mat.Cols - pad; c_col++) { k = 0; for (int k_row = 0; k_row < kernel_size; k_row++) // k - kernel { for (int k_col = 0; k_col < kernel_size; k_col++) { vector[k] = idx[c_row - pad + k_row, c_col - pad + k_col]; k++; } } idx[c_row, c_col] = (byte)Median(vector); } } return(outputImg); }
/// <summary> /// Nickの手法による二値化処理を行う。 /// </summary> /// <param name="imgSrc">入力画像</param> /// <param name="imgDst">出力画像</param> /// <param name="kernelSize">局所領域のサイズ</param> /// <param name="k">係数</param> #else /// <summary> /// Binarizes by Nick's method /// </summary> /// <param name="src">Input image</param> /// <param name="dst">Output image</param> /// <param name="kernelSize">Window size</param> /// <param name="k">Adequate coefficient</param> #endif public static void Nick(Mat src, Mat dst, int kernelSize, double k) { if (src == null) { throw new ArgumentNullException("src"); } if (dst == null) { throw new ArgumentNullException("dst"); } // グレースケールのみ if (src.Type() != MatType.CV_8UC1) { throw new ArgumentException("src must be gray scale image"); } if (dst.Type() != MatType.CV_8UC1) { throw new ArgumentException("dst must be gray scale image"); } // サイズのチェック if (kernelSize < 3) { throw new ArgumentOutOfRangeException("kernelSize", "size must be 3 and above"); } if (kernelSize % 2 == 0) { throw new ArgumentOutOfRangeException("kernelSize", "size must be odd number"); } int borderSize = kernelSize / 2; int width = src.Width; int height = src.Height; dst.Create(src.Size(), src.Type()); using (var tempMat = new Mat(height + (borderSize * 2), width + (borderSize * 2), src.Type())) using (var sumMat = new Mat(tempMat.Height + 1, tempMat.Width + 1, MatType.CV_64FC1, 1)) using (var sqSumMat = new Mat(tempMat.Height + 1, tempMat.Width + 1, MatType.CV_64FC1, 1)) { Cv2.CopyMakeBorder(src, tempMat, borderSize, borderSize, borderSize, borderSize, BorderTypes.Replicate, Scalar.All(0)); Cv2.Integral(tempMat, sumMat, sqSumMat); using (var tSrcMat = new MatOfByte(src)) using (var tDstMat = new MatOfByte(dst)) using (var tSumMat = new MatOfDouble(sumMat)) using (var tSqSumMat = new MatOfDouble(sqSumMat)) { var tSrc = tSrcMat.GetIndexer(); var tDst = tDstMat.GetIndexer(); var tSum = tSumMat.GetIndexer(); var tSqSum = tSqSumMat.GetIndexer(); int ylim = height + borderSize; int xlim = width + borderSize; int kernelPixels = kernelSize * kernelSize; for (int y = borderSize; y < ylim; y++) { for (int x = borderSize; x < xlim; x++) { int x1 = x - borderSize; int y1 = y - borderSize; int x2 = x + borderSize + 1; int y2 = y + borderSize + 1; double sum = tSum[y2, x2] - tSum[y2, x1] - tSum[y1, x2] + tSum[y1, x1]; double sqsum = tSqSum[y2, x2] - tSqSum[y2, x1] - tSqSum[y1, x2] + tSqSum[y1, x1]; double mean = sum / kernelPixels; double term = (sqsum - mean * mean) / kernelPixels; if (term < 0.0) { term = 0.0; } term = Math.Sqrt(term); double threshold = mean + k * term; if (tSrc[y - borderSize, x - borderSize] < threshold) { tDst[y - borderSize, x - borderSize] = 0; } else { tDst[y - borderSize, x - borderSize] = 255; } } } } } }
/// <summary> /// Bernsenの手法による二値化処理を行う。 /// </summary> /// <param name="imgSrc">入力画像</param> /// <param name="imgDst">出力画像</param> /// <param name="kernelSize">局所領域のサイズ</param> /// <param name="constrastMin">この数値以下のコントラストの領域は背景領域とみなす</param> /// <param name="bgThreshold">背景領域と見なされた領域に適用する閾値(背景領域以外では、適応的に閾値を求める)</param> #else /// <summary> /// Binarizes by Bernsen's method /// </summary> /// <param name="src">Input image</param> /// <param name="dst">Output image</param> /// <param name="kernelSize">Window size</param> /// <param name="constrastMin">Adequate coefficient</param> /// <param name="bgThreshold">Adequate coefficient</param> #endif public static void Bernsen(Mat src, Mat dst, int kernelSize, byte constrastMin, byte bgThreshold) { if (src == null) { throw new ArgumentNullException("src"); } if (dst == null) { throw new ArgumentNullException("dst"); } // グレースケールのみ if (src.Type() != MatType.CV_8UC1) { throw new ArgumentException("src must be gray scale image"); } if (dst.Type() != MatType.CV_8UC1) { throw new ArgumentException("dst must be gray scale image"); } // サイズのチェック if (kernelSize < 3) { throw new ArgumentOutOfRangeException("kernelSize", "size must be 3 and above"); } if (kernelSize % 2 == 0) { throw new ArgumentOutOfRangeException("kernelSize", "size must be odd number"); } int width = src.Width; int height = src.Height; dst.Create(src.Size(), src.Type()); using (var tSrcMat = new MatOfByte(src)) using (var tDstMat = new MatOfByte(dst)) { var tSrc = tSrcMat.GetIndexer(); var tDst = tDstMat.GetIndexer(); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { byte min, max; MinMax(src, x, y, kernelSize, out min, out max); int contrast = max - min; byte threshold; if (contrast < constrastMin) { threshold = bgThreshold; } else { threshold = (byte)((max + min) / 2); } if (tSrc[y, x] <= threshold) { tDst[y, x] = 0; } else { tDst[y, x] = 255; } } } } }
/// <summary> /// Niblackの手法による二値化処理を行う。 /// </summary> /// <param name="imgSrc">入力画像</param> /// <param name="imgDst">出力画像</param> /// <param name="kernelSize">局所領域のサイズ</param> /// <param name="k">係数</param> #else /// <summary> /// Binarizes by Niblack's method /// </summary> /// <param name="src">Input image</param> /// <param name="dst">Output image</param> /// <param name="kernelSize">Window size</param> /// <param name="k">Adequate coefficient</param> #endif public static void Niblack(Mat src, Mat dst, int kernelSize, double k) { if (src == null) { throw new ArgumentNullException("src"); } if (dst == null) { throw new ArgumentNullException("dst"); } // グレースケールのみ if (src.Type() != MatType.CV_8UC1) { throw new ArgumentException("src must be gray scale image"); } if (dst.Type() != MatType.CV_8UC1) { throw new ArgumentException("dst must be gray scale image"); } // サイズのチェック if (kernelSize < 3) { throw new ArgumentOutOfRangeException("kernelSize", "size must be 3 and above"); } if (kernelSize % 2 == 0) { throw new ArgumentOutOfRangeException("kernelSize", "size must be odd number"); } int width = src.Width; int height = src.Height; dst.Create(src.Size(), src.Type()); using (var tSrcMat = new MatOfByte(src)) using (var tDstMat = new MatOfByte(dst)) { var tSrc = tSrcMat.GetIndexer(); var tDst = tDstMat.GetIndexer(); //for (int y = 0; y < gray.Height; y++) MyParallel.For(0, height, delegate(int y) { for (int x = 0; x < width; x++) { double m, s; MeanStddev(src, x, y, kernelSize, out m, out s); double threshold = m + k * s; if (tSrc[y, x] < threshold) { tDst[y, x] = 0; } else { tDst[y, x] = 255; } } } ); } }
/// <summary> /// Niblackの手法による二値化処理を行う(高速だが、メモリを多く消費するバージョン)。 /// </summary> /// <param name="imgSrc">入力画像</param> /// <param name="imgDst">出力画像</param> /// <param name="kernelSize">局所領域のサイズ</param> /// <param name="k">係数</param> #else /// <summary> /// Binarizes by Niblack's method (This is faster but memory-hogging) /// </summary> /// <param name="src">Input image</param> /// <param name="dst">Output image</param> /// <param name="kernelSize">Window size</param> /// <param name="k">Adequate coefficient</param> #endif public static void NiblackFast(Mat src, Mat dst, int kernelSize, double k) { if (src == null) throw new ArgumentNullException("src"); if (dst == null) throw new ArgumentNullException("dst"); // グレースケールのみ if (src.Type() != MatType.CV_8UC1) throw new ArgumentException("src must be gray scale image"); if (dst.Type() != MatType.CV_8UC1) throw new ArgumentException("dst must be gray scale image"); // サイズのチェック if (kernelSize < 3) throw new ArgumentOutOfRangeException("kernelSize", "size must be 3 and above"); if (kernelSize % 2 == 0) throw new ArgumentOutOfRangeException("kernelSize", "size must be odd number"); int borderSize = kernelSize / 2; int width = src.Width; int height = src.Height; dst.Create(src.Size(), src.Type()); using (var tempMat = new Mat(height + (borderSize * 2), width + (borderSize * 2), src.Type())) using (var sumMat = new Mat(tempMat.Height + 1, tempMat.Width + 1, MatType.CV_64FC1, 1)) using (var sqSumMat = new Mat(tempMat.Height + 1, tempMat.Width + 1, MatType.CV_64FC1, 1)) { Cv2.CopyMakeBorder(src, tempMat, borderSize, borderSize, borderSize, borderSize, BorderTypes.Replicate, Scalar.All(0)); Cv2.Integral(tempMat, sumMat, sqSumMat); using (var tSrcMat = new MatOfByte(src)) using (var tDstMat = new MatOfByte(dst)) using (var tSumMat = new MatOfDouble(sumMat)) using (var tSqSumMat = new MatOfDouble(sqSumMat)) { var tSrc = tSrcMat.GetIndexer(); var tDst = tDstMat.GetIndexer(); var tSum = tSumMat.GetIndexer(); var tSqSum = tSqSumMat.GetIndexer(); int ylim = height + borderSize; int xlim = width + borderSize; int kernelPixels = kernelSize * kernelSize; for (int y = borderSize; y < ylim; y++) { for (int x = borderSize; x < xlim; x++) { int x1 = x - borderSize; int y1 = y - borderSize; int x2 = x + borderSize + 1; int y2 = y + borderSize + 1; double sum = tSum[y2, x2] - tSum[y2, x1] - tSum[y1, x2] + tSum[y1, x1]; double sqsum = tSqSum[y2, x2] - tSqSum[y2, x1] - tSqSum[y1, x2] + tSqSum[y1, x1]; double mean = sum / kernelPixels; double var = (sqsum / kernelPixels) - (mean * mean); if (var < 0.0) var = 0.0; double stddev = Math.Sqrt(var); double threshold = mean + k * stddev; if (tSrc[y - borderSize, x - borderSize] < threshold) tDst[y - borderSize, x - borderSize] = 0; else tDst[y - borderSize, x - borderSize] = 255; } } } } }
/// <summary> /// 注目画素の周辺画素の最大値と最小値を求める /// </summary> /// <param name="img">画像の画素データ</param> /// <param name="x">x座標</param> /// <param name="y">y座標</param> /// <param name="size">周辺画素の探索サイズ。奇数でなければならない</param> /// <param name="min">出力される最小値</param> /// <param name="max">出力される最大値</param> private static void MinMax(Mat img, int x, int y, int size, out byte min, out byte max) { int size2 = size / 2; min = byte.MaxValue; max = byte.MinValue; int xs = Math.Max(x - size2, 0); int xe = Math.Min(x + size2, img.Width); int ys = Math.Max(y - size2, 0); int ye = Math.Min(y + size2, img.Height); using (var tImg = new MatOfByte(img)) { var indexer = tImg.GetIndexer(); for (int xx = xs; xx < xe; xx++) { for (int yy = ys; yy < ye; yy++) { byte v = indexer[yy, xx]; if (max < v) max = v; else if (min > v) min = v; } } } }
/// <summary> /// 注目画素の周辺画素の平均値と標準偏差を求める /// </summary> /// <param name="img">画像の画素データ</param> /// <param name="x">x座標</param> /// <param name="y">y座標</param> /// <param name="size">周辺画素の探索サイズ。奇数でなければならない</param> /// <param name="mean">出力される平均</param> /// <param name="stddev">出力される標準偏差</param> private static void MeanStddev(Mat img, int x, int y, int size, out double mean, out double stddev) { int count = 0; int sum = 0; int sqsum = 0; int size2 = size / 2; int xs = Math.Max(x - size2, 0); int xe = Math.Min(x + size2, img.Width); int ys = Math.Max(y - size2, 0); int ye = Math.Min(y + size2, img.Height); byte v; using (var tImg = new MatOfByte(img)) { var indexer = tImg.GetIndexer(); for (int xx = xs; xx < xe; xx++) { for (int yy = ys; yy < ye; yy++) { v = indexer[yy, xx]; sum += v; sqsum += v*v; count++; } } } mean = (double)sum / count; double var = ((double)sqsum / count) - (mean * mean); if (var < 0.0) var = 0.0; stddev = Math.Sqrt(var); }
/// <summary> /// Bernsenの手法による二値化処理を行う。 /// </summary> /// <param name="imgSrc">入力画像</param> /// <param name="imgDst">出力画像</param> /// <param name="kernelSize">局所領域のサイズ</param> /// <param name="constrastMin">この数値以下のコントラストの領域は背景領域とみなす</param> /// <param name="bgThreshold">背景領域と見なされた領域に適用する閾値(背景領域以外では、適応的に閾値を求める)</param> #else /// <summary> /// Binarizes by Bernsen's method /// </summary> /// <param name="src">Input image</param> /// <param name="dst">Output image</param> /// <param name="kernelSize">Window size</param> /// <param name="constrastMin">Adequate coefficient</param> /// <param name="bgThreshold">Adequate coefficient</param> #endif public static void Bernsen(Mat src, Mat dst, int kernelSize, byte constrastMin, byte bgThreshold) { if (src == null) throw new ArgumentNullException("src"); if (dst == null) throw new ArgumentNullException("dst"); // グレースケールのみ if (src.Type() != MatType.CV_8UC1) throw new ArgumentException("src must be gray scale image"); if (dst.Type() != MatType.CV_8UC1) throw new ArgumentException("dst must be gray scale image"); // サイズのチェック if (kernelSize < 3) throw new ArgumentOutOfRangeException("kernelSize", "size must be 3 and above"); if (kernelSize % 2 == 0) throw new ArgumentOutOfRangeException("kernelSize", "size must be odd number"); int width = src.Width; int height = src.Height; dst.Create(src.Size(), src.Type()); using (var tSrcMat = new MatOfByte(src)) using (var tDstMat = new MatOfByte(dst)) { var tSrc = tSrcMat.GetIndexer(); var tDst = tDstMat.GetIndexer(); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { byte min, max; MinMax(src, x, y, kernelSize, out min, out max); int contrast = max - min; byte threshold; if (contrast < constrastMin) threshold = bgThreshold; else threshold = (byte)((max + min) / 2); if (tSrc[y, x] <= threshold) tDst[y, x] = 0; else tDst[y, x] = 255; } } } }
public static float[] GetArray(this Mat self, float[] buffer = null, bool bgr2rgb = true) { int width = self.Width; int height = self.Height; float[] f; if (buffer == null) { f = new float[width * height * self.Channel]; } else { if (buffer.Length < width * height * self.Channel) { throw new ArgumentOutOfRangeException(nameof(buffer)); } f = buffer; } if (self.Channel == 3) { using (MatOfByte3 matByte = new MatOfByte3()) { self.CopyTo(matByte); var indexer = matByte.GetIndexer(); int i = 0; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { Vec3b color = indexer[y, x]; if (bgr2rgb) { f[i] = color.Item2; i++; f[i] = color.Item1; i++; f[i] = color.Item0; i++; } else { f[i] = color.Item0; i++; f[i] = color.Item1; i++; f[i] = color.Item2; i++; } } } } } else if (self.Channel == 1) { using (var matByte = new MatOfByte()) { self.CopyTo(matByte); var w = self.Width; var h = self.Height; var indexer = matByte.GetIndexer(); int i = 0; for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { var pixel = indexer[y, x]; f[i] = pixel; i++; } } } } else { throw new Exception("not supported channel"); } return(f); }
public Dictionary <string, string> DecodeQRCode(QRCodeProperties qrCodeProps, QRColorMode colorMode) { outputMessages = new Dictionary <string, string>(); if (colorMode == QRColorMode.Grayscale) { string decodedBinary = string.Empty; outputMats.TryGetValue(QR_TYPE_MONOCHROME, out Mat qrMatMono); // Get mat indexer MatOfByte mob1 = new MatOfByte(qrMatMono); MatIndexer <byte> indexerByte = mob1.GetIndexer(); // Read decoded strings int bitsPerChar = 7; int messageLength = inputMessage.Length; decimal messageChars = messageLength / bitsPerChar; // Read decoded binary for (int i = 0; i < messageChars; i++) { decodedBinary += ReadMonochromePixels(indexerByte, i, bitsPerChar); } // Add decoded messag to output list outputMessages.Add(QR_TYPE_MONOCHROME, decodedBinary); return(outputMessages); } else if (colorMode == QRColorMode.Color) { string decodedBinaryRed = string.Empty; string decodedBinaryGreen = string.Empty; string decodedBinaryBlue = string.Empty; string decodedBinaryCombined = string.Empty; outputMats.TryGetValue(QR_TYPE_COMBINED, out Mat qrMatCombined); // Get mat indexer MatOfByte3 mobComb = new MatOfByte3(qrMatCombined); MatIndexer <Vec3b> indexerMobComb = mobComb.GetIndexer(); // Read decoded strings int bitsPerChar = 7; int messageLength = inputMessage.Length; decimal messageChars = messageLength / bitsPerChar; int coloredMessageLength = (int)Math.Ceiling(messageChars / 3); for (int i = 0; i < coloredMessageLength; i++) { string tempRed = ReadColorPixels(indexerMobComb, QR_TYPE_RED, i, bitsPerChar); string tempGreen = ReadColorPixels(indexerMobComb, QR_TYPE_GREEN, i, bitsPerChar); string tempBlue = ReadColorPixels(indexerMobComb, QR_TYPE_BLUE, i, bitsPerChar); decodedBinaryRed += tempRed; decodedBinaryGreen += tempGreen; decodedBinaryBlue += tempBlue; decodedBinaryCombined += tempRed; decodedBinaryCombined += tempGreen; decodedBinaryCombined += tempBlue; } // Add output messages outputMessages.Add(QR_TYPE_RED, decodedBinaryRed); outputMessages.Add(QR_TYPE_GREEN, decodedBinaryGreen); outputMessages.Add(QR_TYPE_BLUE, decodedBinaryBlue); outputMessages.Add(QR_TYPE_COMBINED, decodedBinaryCombined); return(outputMessages); } return(null); }
public Dictionary <string, BitmapSource> GenerateQRCore(string inputMessage, QRCodeProperties qrCodeProps, QRColorMode colorMode) { outputImages = new Dictionary <string, BitmapSource>(); outputMats = new Dictionary <string, Mat>(); matSearchPixels = new List <Point>(); this.inputMessage = inputMessage; CalculateSearchPoint(qrCodeProps); if (colorMode == QRColorMode.Grayscale) { // Generate empty mat and set all pixels to white qrMatMono = Mat.Zeros(new Size(qrCodeProps.ImgSize.Width, qrCodeProps.ImgSize.Height), MatType.CV_8UC1); //qrMat.SetTo(Scalar.White); // Get mat indexer MatOfByte mob1 = new MatOfByte(qrMatMono); MatIndexer <byte> indexerByte = mob1.GetIndexer(); int stringIndex = -1; for (int y = 0; y < qrCodeProps.CellsPerDim * qrCodeProps.CellSize; y += qrCodeProps.CellSize) { for (int x = 0; x < qrCodeProps.CellsPerDim * qrCodeProps.CellSize; x += qrCodeProps.CellSize) { // If message is done reading if (++stringIndex + 1 > inputMessage.Length) { break; } // If bit is 0, skip this cell if (inputMessage[stringIndex].Equals('0')) { continue; } // If bit is 1, color the cell else if (inputMessage[stringIndex].Equals('1')) { for (int i = y; i < y + qrCodeProps.CellSize; i++) { for (int j = x; j < x + qrCodeProps.CellSize; j++) { indexerByte[i, j] = LUM_INTENSITY_MAX; } } } } } // Add image and mat to output lists outputImages.Add(QR_TYPE_MONOCHROME, Utils.MatToImage(qrMatMono)); outputMats.Add(QR_TYPE_MONOCHROME, qrMatMono); // Return images to UI return(outputImages); } else if (colorMode == QRColorMode.Color) { // Generate empty mats and fill with white Mat qrRedMat = Mat.Zeros(new Size(qrCodeProps.ImgSize.Width, qrCodeProps.ImgSize.Height), MatType.CV_8UC3); Mat qrGreenMat = Mat.Zeros(new Size(qrCodeProps.ImgSize.Width, qrCodeProps.ImgSize.Height), MatType.CV_8UC3); Mat qrBlueMat = Mat.Zeros(new Size(qrCodeProps.ImgSize.Width, qrCodeProps.ImgSize.Height), MatType.CV_8UC3); //qrCyanMat.SetTo(Scalar.White); //qrMagentaMat.SetTo(Scalar.White); //qrYellowMat.SetTo(Scalar.White); // Get mat indexers MatOfByte3 mobRed = new MatOfByte3(qrRedMat); MatOfByte3 mobGreen = new MatOfByte3(qrGreenMat); MatOfByte3 mobBlue = new MatOfByte3(qrBlueMat); MatIndexer <Vec3b> indexerMobRed = mobRed.GetIndexer(); MatIndexer <Vec3b> indexerMobGreen = mobGreen.GetIndexer(); MatIndexer <Vec3b> indexerMobBlue = mobBlue.GetIndexer(); // Split message thrice int bitsPerChar = 7; int messageChars = inputMessage.Length / bitsPerChar; string messageForRed = string.Empty; string messageForGreen = string.Empty; string messageForBlue = string.Empty; for (int i = 0; i < messageChars; i++) { if (i % 3 == 0) { for (int j = 0; j < bitsPerChar; j++) { messageForRed += inputMessage[(i * bitsPerChar) + j]; } } else if (i % 3 == 1) { for (int j = 0; j < bitsPerChar; j++) { messageForGreen += inputMessage[(i * bitsPerChar) + j]; } } else if (i % 3 == 2) { for (int j = 0; j < bitsPerChar; j++) { messageForBlue += inputMessage[(i * bitsPerChar) + j]; } } } indexerMobRed = WriteColorComponent(messageForRed, qrCodeProps, indexerMobRed, COLOR_RED); indexerMobGreen = WriteColorComponent(messageForGreen, qrCodeProps, indexerMobGreen, COLOR_GREEN); indexerMobBlue = WriteColorComponent(messageForBlue, qrCodeProps, indexerMobBlue, COLOR_BLUE); Mat combinedMat = qrRedMat + qrGreenMat + qrBlueMat; // Add image and mats to output lists outputImages.Add(QR_TYPE_COMBINED, Utils.MatToImage(combinedMat)); outputImages.Add(QR_TYPE_RED, Utils.MatToImage(qrRedMat)); outputImages.Add(QR_TYPE_GREEN, Utils.MatToImage(qrGreenMat)); outputImages.Add(QR_TYPE_BLUE, Utils.MatToImage(qrBlueMat)); outputMats.Add(QR_TYPE_COMBINED, combinedMat); outputMats.Add(QR_TYPE_RED, qrRedMat); outputMats.Add(QR_TYPE_GREEN, qrGreenMat); outputMats.Add(QR_TYPE_BLUE, qrBlueMat); return(outputImages); } return(null); }
static void Main(string[] args) { // Used to check memory leak //for (int i = 0; i < 1000; i++) using (var state = new ThreadLocal <FormExtractionHandle>(NativeFormExtraction.CreateFormExtraction)) { GC.Collect(); List <string> pathFiles = GetSamplesAndCleanUpResults(); // For testing: pathFiles = pathFiles.Where(m => m.Contains("form9")).ToList(); int numThread = 1; // Environment.ProcessorCount; var showDebugImage = true; // If true, you may want to use: numThread = 1. Parallel.ForEach(pathFiles, new ParallelOptions { MaxDegreeOfParallelism = numThread }, pathFile => { FormExtractionHandle handle = state.Value; NativeFormExtraction.SetOptions(handle, 800, 25, 15, 5, 20000, 50000, showDebugImage); var resizeWidth = 800; var orig = new Mat(pathFile); var image = new Mat(pathFile, ImreadModes.GrayScale); Cv2.AdaptiveThreshold(image, image, 255, AdaptiveThresholdTypes.MeanC, ThresholdTypes.Binary, 9, 4); // Resize image if too large. if (image.Width > resizeWidth) { var height = resizeWidth * image.Height / image.Width; Cv2.Resize(image, image, new Size(resizeWidth, height)); } Cv2.BitwiseNot(image, image); Cv2.Dilate(image, image, Cv2.GetStructuringElement(MorphShapes.Cross, new Size(2, 2))); MatOfByte mat = new MatOfByte(image); MatIndexer <byte> indexer = mat.GetIndexer(); var row = image.Height; var col = image.Width; Mat newImage = new Mat(row, col, MatType.CV_8UC3); newImage.SetTo(Scalar.Black); // We must determine if it "may" be an interesting blob. Stopwatch watch = new Stopwatch(); watch.Start(); int[] imgData = new int[row * col]; for (int y = 0; y < row; y++) { for (int x = 0; x < col; x++) { imgData[y + x * row] = indexer[y, x]; } } var result = NativeFormExtraction.RunFormExtraction(handle, imgData, row, col); if (result != 0) { throw new Exception("Unknown error occured with the function: RunFormExtraction"); } watch.Stop(); Console.WriteLine("Duration: " + watch.Elapsed); if (showDebugImage) { var debugImg = NativeFormExtraction.GetDebugImage(handle, row * col); var img = CreateImage(debugImg, row, col, hasColor: true); Cv2.BitwiseOr(newImage, img, newImage); Cv2.BitwiseNot(image, image); int width = 400; var height = width * image.Height / image.Width; Cv2.Resize(orig, orig, new Size(width, height)); Cv2.Resize(image, image, new Size(width, height)); Cv2.Resize(newImage, newImage, new Size(width, height)); using (new Window("orig", orig)) using (new Window("pre", image)) using (new Window("post", newImage)) { Cv2.WaitKey(); Cv2.DestroyAllWindows(); } } // Dispose. orig.Dispose(); image.Dispose(); newImage.Dispose(); mat.Dispose(); }); } Console.WriteLine("End"); Console.ReadLine(); }
public static FormExtractionResult ProcessImage(string filename, FormExtractionOptions options = null) { if (options == null) { // Assume recommanded parameters. options = new FormExtractionOptions(); } var orig = new Mat(filename); var image = new Mat(filename, ImreadModes.GrayScale); Cv2.AdaptiveThreshold(image, image, 255, AdaptiveThresholdTypes.MeanC, ThresholdTypes.Binary, 9, 4); // Resize image if too large. if (image.Width > options.ResizeWidth) { var height = options.ResizeWidth * image.Height / image.Width; Cv2.Resize(image, image, new Size(options.ResizeWidth, height)); } Cv2.BitwiseNot(image, image); Cv2.Dilate(image, image, Cv2.GetStructuringElement(MorphShapes.Cross, new Size(2, 2))); MatOfByte mat = new MatOfByte(image); MatIndexer <byte> indexer = mat.GetIndexer(); var row = image.Height; var col = image.Width; Mat newImage = new Mat(row, col, MatType.CV_8UC3); newImage.SetTo(Scalar.Black); // We must determine if it "may" be an interesting blob. Stopwatch watch = new Stopwatch(); watch.Start(); int[] imgData = new int[row * col]; for (int y = 0; y < row; y++) { for (int x = 0; x < col; x++) { imgData[y + x * row] = indexer[y, x]; } } var result = HasBoxes(imgData, row, col, options); watch.Stop(); result.Duration = watch.Elapsed; // Preview if (result.Boxes.Any() && image.Width != 0 && options.ShowDebugImage) { var img = CreateImage(result.DebugImg, hasColor: true); Cv2.BitwiseOr(newImage, img, newImage); Cv2.BitwiseNot(image, image); int width = 400; var height = width * image.Height / image.Width; Cv2.Resize(orig, orig, new Size(width, height)); Cv2.Resize(image, image, new Size(width, height)); Cv2.Resize(newImage, newImage, new Size(width, height)); using (new Window("orig", orig)) using (new Window("pre", image)) using (new Window("post", newImage)) { Cv2.WaitKey(); Cv2.DestroyAllWindows(); } } // Dispose. orig.Dispose(); image.Dispose(); newImage.Dispose(); mat.Dispose(); return(result); }