/// <summary> /// Вычисление градиента изображения /// </summary> /// <param name="image">Изображение</param> private void CountGradient(GreyImage image) { try { GreyImage copyImage = (GreyImage)image.Copy(); int imageHeight = image.Height - 1; int imageWidth = image.Width - 1; for (int i = 0; i < imageHeight; i++) for (int j = 0; j < imageWidth; j++) { int gradientX = Math.Abs(copyImage.Pixels[i, j].Color.Data - copyImage.Pixels[i + 1, j].Color.Data); int gradientY = Math.Abs(copyImage.Pixels[i, j].Color.Data - copyImage.Pixels[i, j + 1].Color.Data); int gradient = gradientX + gradientY; if (gradient > ColorBase.MAX_COLOR_VALUE) gradient = ColorBase.MAX_COLOR_VALUE; image.Pixels[i, j].Color.Data = (byte) gradient; } } catch (Exception exception) { throw exception; } }
/// <summary> /// Бинаризация методом Ниблака /// </summary> /// <param name="image"></param> public void Binarize(GreyImage image) { try { int windowSize = this.WindowSize; int lowIndex = windowSize / 2; int highIndexI = image.Height - lowIndex; int highIndexJ = image.Width - lowIndex; GreyImage copyImage = (GreyImage)image.Copy(); for (int i = lowIndex; i < highIndexI; i++) for (int j = lowIndex; j < highIndexJ; j++) { double matExp = CountMatExp(copyImage, i, j); double sigma = CountSigma(copyImage, i, j, matExp); int treshold = (int) (matExp + this.K * sigma); if (image.Pixels[i, j].Color.Data < treshold) image.Pixels[i, j].Color.Data = (byte)ColorBase.MIN_COLOR_VALUE; else image.Pixels[i, j].Color.Data = (byte)ColorBase.MAX_COLOR_VALUE; } } catch (Exception exception) { throw exception; } }
/// <summary> /// Применение морфологической операции расширения к контурному изображению /// </summary> /// <param name="image"></param> public override void Apply(GreyImage image) { try { if (image == null) throw new ArgumentNullException("Null image in Apply"); GreyImage copyImage = (GreyImage)image.Copy(); int filterSize = this.Size; int lowIndex = filterSize / 2; int highIndexI = image.Height; int highIndexJ = image.Width - lowIndex; for (int i = 0; i < highIndexI; i++) for (int j = lowIndex; j < highIndexJ; j++) { if (copyImage.Pixels[i, j].Color.Data == ColorBase.MIN_COLOR_VALUE) { //ool borderPixelFound = false; for (int k = 0; k < filterSize; k++) image.Pixels[i, k + j - lowIndex].Color.Data = (byte)ColorBase.MIN_COLOR_VALUE; // (copyImage.Pixels[i, k + j - lowIndex].Color.Data == ColorBase.MIN_COLOR_VALUE) //borderPixelFound = true; // if (borderPixelFound) // image.Pixels[i, j].Color.Data = (byte) ColorBase.MIN_COLOR_VALUE; } } } catch (Exception exception) { throw exception; } }
/// <summary> /// Применение SWT фильтра к серому изображению /// </summary> /// <param name="image">Серое изображение</param> public override void Apply(GreyImage image) { try { if (image == null) throw new ArgumentNullException("Null image in Apply"); if (image.Height != this._gaussSmoothedImage.Height || image.Width != this._gaussSmoothedImage.Width) throw new ArgumentException("Image must be the same size with gaussSmoothedImage in ctor"); this._maxIntensityDirectionImage = (GreyImage) image.Copy(); if (this._maxIntensityDirectionImage == null) throw new NullReferenceException("Null _minIntensityDirectionImage in Apply"); this._minIntensityDirectionImage = (GreyImage)image.Copy(); if (this._minIntensityDirectionImage == null) throw new NullReferenceException("Null _minIntensityDirectionImage in Apply"); FillMinIntensityImage(image); FillMaxIntensityImage(image); } catch (Exception exception) { throw exception; } }
/// <summary> /// Применение фильтра Лапласа к серому изображению /// </summary> /// <param name="image">Серое изображение</param> public override void Apply(GreyImage image) { try { if (image == null) throw new ArgumentNullException("Null image in Apply"); if (image.Height < this.Size) throw new ArgumentException("Image height must be >= filter size"); if (image.Width < this.Size) throw new ArgumentException("Image width must be >= filter size"); GreyImage copyImage = (GreyImage)image.Copy(); if (copyImage == null) throw new NullReferenceException("Null copy image in Apply"); int lowIndex = Size / 2; int highIndexI = image.Height - lowIndex; int highIndexJ = image.Width - lowIndex; for (int i = lowIndex; i < highIndexI; i++) for (int j = lowIndex; j < highIndexJ; j++) { int gradientStrengthX = copyImage.Pixels[i - 1, j].Color.Data * Gx[0, 1] + copyImage.Pixels[i, j - 1].Color.Data * Gx[1, 0] + copyImage.Pixels[i, j].Color.Data * Gx[1, 1] + copyImage.Pixels[i, j + 1].Color.Data * Gx[1, 2] + copyImage.Pixels[i + 1, j].Color.Data * Gx[2, 1]; int gradientStrengthSqr = gradientStrengthX * gradientStrengthX + gradientStrengthX * gradientStrengthX; if (gradientStrengthSqr > ColorBase.MAX_COLOR_VALUE) { image.Pixels[i, j].Color.Data = (byte)ColorBase.MIN_COLOR_VALUE; image.Pixels[i, j].BorderType = BorderType.Border.STRONG; } else { image.Pixels[i, j].Color.Data = (byte)ColorBase.MAX_COLOR_VALUE; image.Pixels[i, j].BorderType = BorderType.Border.WEAK; } } } catch (Exception exception) { throw exception; } }
/// <summary> /// Применение фильтра Гаусса к серому изображению /// </summary> /// <param name="image">Серое изображение</param> public override void Apply(GreyImage image) { try { if (image == null) throw new ArgumentNullException("Null image in Apply"); if (image.Height < this.Size) throw new ArgumentException("Image height must be >= filter size"); if (image.Width < this.Size) throw new ArgumentException("Image width must be >= filter size"); GreyImage copyImage = (GreyImage) image.Copy(); if (copyImage == null) throw new NullReferenceException("Null copy image in Apply"); int filterSize = this.Size; int lowIndex = filterSize / 2; int highIndexI = image.Height - lowIndex; int highIndexJ = image.Width - lowIndex; for (int i = lowIndex; i < highIndexI; i++) for (int j = lowIndex; j < highIndexJ; j++) { int pixelColor = 0; for (int k = 0; k < filterSize; k++) for (int l = 0; l < filterSize; l++) pixelColor += this.Kernel[k, l] * copyImage.Pixels[k + i - lowIndex, l + j - lowIndex].Color.Data; pixelColor /= this.NormalizationRatio; if (pixelColor > ColorBase.MAX_COLOR_VALUE) pixelColor = ColorBase.MAX_COLOR_VALUE; if (pixelColor < 0) pixelColor = ColorBase.MIN_COLOR_VALUE; image.Pixels[i, j].Color.Data = (byte) pixelColor; } } catch (Exception exception) { throw exception; } }
/// <summary> /// Применение морфологической операции эрозии к контурному изображению /// </summary> /// <param name="image"></param> public override void Apply(GreyImage image) { try { if (image == null) throw new ArgumentNullException("Null image in Apply"); GreyImage copyImage = (GreyImage)image.Copy(); int filterSize = this.Size; int lowIndex = filterSize / 2; int highIndexI = image.Height - 1; int highIndexJ = image.Width - lowIndex; for (int i = 1; i < highIndexI; i++) for (int j = lowIndex; j < highIndexJ; j++) { if (copyImage.Pixels[i, j].Color.Data == ColorBase.MIN_COLOR_VALUE) { int pixelsNumber = 0; for (int k = 0; k < filterSize; k++) if (copyImage.Pixels[i, k + j - lowIndex].Color.Data == ColorBase.MIN_COLOR_VALUE) ++pixelsNumber; if (pixelsNumber == filterSize) { for (int k = 0; k < lowIndex; k++) image.Pixels[i, k + j - lowIndex].Color.Data = (byte)ColorBase.MAX_COLOR_VALUE; for (int k = lowIndex + 1; k < filterSize; k++) image.Pixels[i, k + j - lowIndex].Color.Data = (byte)ColorBase.MAX_COLOR_VALUE; image.Pixels[i, j].Color.Data = (byte)ColorBase.MIN_COLOR_VALUE; } } } } catch (Exception exception) { throw exception; } }
/// <summary> /// Применение фильтра Гаусса к серому изображению (многопоточная) /// </summary> /// <param name="image">Серое изображение</param> /// <param name="threadsNumber">Число потоков</param> public override GreyImage Apply(GreyImage image, int threadsNumber) { try { if (image == null) throw new ArgumentNullException("Null image in Apply"); if (image.Height < this.Size) throw new ArgumentException("Image height must be >= filter size"); if (image.Width < this.Size) throw new ArgumentException("Image width must be >= filter size"); if (threadsNumber <= 0) throw new ArgumentException("Error threadsNumber in Apply"); this._copyImage = (GreyImage)image.Copy(); if (this._copyImage == null) throw new NullReferenceException("Null copy image in Apply"); this.Threads = new List<Thread>(); int deltaI = image.Height / threadsNumber; int filterSize = this.Size; int lowIndex = filterSize / 2; int lowIndexI = lowIndex; int highIndexI = lowIndexI + deltaI; int highIndexJ = image.Width - lowIndex; for (int i = 0; i < threadsNumber; i++) { if (i == threadsNumber - 1) highIndexI = image.Height - lowIndex; MatrixFilterData matrixFilterData = new ThreadData.MatrixFilterData(image, lowIndexI, highIndexI, lowIndex, highIndexJ); Thread thread = new Thread(new ParameterizedThreadStart(this.ApplyThread)); this.Threads.Add(thread); this.Threads[i].Start(matrixFilterData); lowIndexI = highIndexI; highIndexI += deltaI; } WaitForThreads(); return this._copyImage; } catch (Exception exception) { throw exception; } }
/// <summary> /// Применение фильтра Превитта к серому изображению /// </summary> /// <param name="image">Серое изображение</param> public override void Apply(GreyImage image) { try { if (image == null) throw new ArgumentNullException("Null image in Apply"); if (image.Height < this.Size) throw new ArgumentException("Image height must be >= filter size"); if (image.Width < this.Size) throw new ArgumentException("Image width must be >= filter size"); GreyImage copyImage = (GreyImage)image.Copy(); if (copyImage == null) throw new NullReferenceException("Null copy image in Apply"); int lowIndex = Size / 2; int highIndexI = image.Height - lowIndex; int highIndexJ = image.Width - lowIndex; for (int i = lowIndex; i < highIndexI; i++) for (int j = lowIndex; j < highIndexJ; j++) { byte pixelI_1J_1 = copyImage.Pixels[i - 1, j - 1].Color.Data; byte pixelI_1J1 = copyImage.Pixels[i - 1, j + 1].Color.Data; byte pixelI1J1 = copyImage.Pixels[i + 1, j + 1].Color.Data; int gradientStrengthY = pixelI_1J_1 * Gy[0, 0] + copyImage.Pixels[i - 1, j].Color.Data * Gy[0, 1] + pixelI_1J1 * Gy[0, 2] + copyImage.Pixels[i + 1, j - 1].Color.Data * Gy[2, 0] + copyImage.Pixels[i + 1, j].Color.Data * Gy[2, 1] + pixelI1J1 * Gy[2, 2]; int gradientStrengthX = pixelI_1J_1 * Gx[0, 0] + pixelI_1J1 * Gx[0, 2] + copyImage.Pixels[i, j - 1].Color.Data * Gx[1, 0] + copyImage.Pixels[i, j + 1].Color.Data * Gx[1, 2] + copyImage.Pixels[i + 1, j - 1].Color.Data * Gx[2, 0] + pixelI1J1 * Gx[2, 2]; int gradientStrengthSqr = gradientStrengthX * gradientStrengthX + gradientStrengthY * gradientStrengthY; image.Pixels[i, j].Gradient.Strength = (int)Math.Sqrt((double)gradientStrengthSqr); if (gradientStrengthSqr > TRESHOLD) { image.Pixels[i, j].Color.Data = (byte)ColorBase.MIN_COLOR_VALUE; image.Pixels[i, j].BorderType = BorderType.Border.STRONG; } else { image.Pixels[i, j].Color.Data = (byte)ColorBase.MAX_COLOR_VALUE; image.Pixels[i, j].BorderType = BorderType.Border.WEAK; } if (gradientStrengthX == 0) { if (gradientStrengthY == 0) image.Pixels[i, j].Gradient.Angle = 0; else image.Pixels[i, j].Gradient.Angle = 90; } else image.Pixels[i, j].Gradient.Angle = (int)((Math.Atan((double)gradientStrengthY / gradientStrengthX)) * (180 / Math.PI)); } } catch (Exception exception) { throw exception; } }
/// <summary> /// Выделение текста на изображении гибрибным подходом /// </summary> /// <param name="image">Изображение</param> public void DetectText(GreyImage image) { try { if (image == null) throw new ArgumentNullException("Null image in DetectText"); // textRegions = null; Thread edgeThread = new Thread(new ParameterizedThreadStart(this.EdgeBasedProcessThread)); Thread gradientThread = new Thread(new ParameterizedThreadStart(this.GradientBasedProcessThread)); GreyImage copyImage = (GreyImage)image.Copy(); edgeThread.Start(copyImage); gradientThread.Start(copyImage); edgeThread.Join(); gradientThread.Join(); for (int i = 0; i < image.Height; i++) for (int j = 0; j < image.Width; j++) { if (this._gradientImage.Pixels[i, j].Color.Data == ColorBase.MAX_COLOR_VALUE && this._edgeImage.Pixels[i, j].Color.Data == ColorBase.MIN_COLOR_VALUE) copyImage.Pixels[i, j].Color.Data = (byte)ColorBase.MIN_COLOR_VALUE; else copyImage.Pixels[i, j].Color.Data = (byte)ColorBase.MAX_COLOR_VALUE; copyImage.Pixels[i, j].BorderType = this._edgeImage.Pixels[i, j].BorderType; // image.Pixels[i, j].Color.Data = this._gradientImage.Pixels[i, j].Color.Data; } this._dilation.Apply(copyImage); int[] heightHist = new int[copyImage.Height]; int[] widthHist = new int[copyImage.Width]; for (int i = 0; i < copyImage.Height; i++) { int sum = 0; for (int j = 0; j < copyImage.Width; j++) { if (copyImage.Pixels[i, j].Color.Data == (byte)ColorBase.MIN_COLOR_VALUE) ++sum; } heightHist[i] = sum; } int maxH = heightHist.Max(); for (int i = 0; i < copyImage.Width; i++) { int sum = 0; for (int j = 0; j < copyImage.Height; j++) { if (copyImage.Pixels[j, i].Color.Data == (byte)ColorBase.MIN_COLOR_VALUE) ++sum; } widthHist[i] = sum; } int maxw = widthHist.Max(); for (int i = 0; i < heightHist.Length; i++) { if (maxH - heightHist[i] < 150) heightHist[i] = 1; else heightHist[i] = 0; } for (int i = 0; i < widthHist.Length; i++) { if (maxw - widthHist[i] < 50) widthHist[i] = 1; else widthHist[i] = 0; } for (int i = 0; i < image.Height; i++) { for (int j = 0; j < image.Width; j++) { if (heightHist[i] == 1 && widthHist[j] == 1) image.Pixels[i, j].Color.Data = (byte)ColorBase.MIN_COLOR_VALUE; // else // image.Pixels[i, j].Color.Data = (byte)ColorBase.MAX_COLOR_VALUE; } } // this._opening.Apply(image); } catch (Exception exception) { throw exception; } }
/// <summary> /// Подавление не максимумов. Границами считаются только точки локального максимума /// </summary> /// <param name="image">Серое изображение</param> private void NonMaximaSuppression(GreyImage image) { try { if (image == null) throw new ArgumentNullException("Null image in NonMaximasuppression"); GreyImage copyImage = (GreyImage)image.Copy(); if (copyImage == null) throw new NullReferenceException("Null copy image in NonMaximaSuppression"); int lowIndex = this.EdgeDetectionFilter.Size / 2; int highIndexI = image.Height - lowIndex; int highIndexJ = image.Width - lowIndex; for (int i = lowIndex; i < highIndexI; i++) for (int j = lowIndex; j < highIndexJ; j++) { GradientData.RoundGradientDirection gradientDirection = image.Pixels[i, j].Gradient.RoundGradientDirection; if (gradientDirection == GradientData.RoundGradientDirection.DEGREE_0) { int gradientStrength = copyImage.Pixels[i, j].Gradient.Strength; if (!(gradientStrength > copyImage.Pixels[i, j - 1].Gradient.Strength && // i, j - 1 gradientStrength > copyImage.Pixels[i, j + 1].Gradient.Strength)) // i, j + 1 image.Pixels[i, j].Gradient.Strength = 0; } else if (gradientDirection == GradientData.RoundGradientDirection.DEGREE__45) { int gradientStrength = copyImage.Pixels[i, j].Gradient.Strength; if (!(gradientStrength > copyImage.Pixels[i + 1, j - 1].Gradient.Strength && gradientStrength > copyImage.Pixels[i - 1, j + 1].Gradient.Strength)) image.Pixels[i, j].Gradient.Strength = 0; } else if (gradientDirection == GradientData.RoundGradientDirection.DEGREE_90) { int gradientStrength = copyImage.Pixels[i, j].Gradient.Strength; if (!(gradientStrength > copyImage.Pixels[i + 1, j].Gradient.Strength && // i + 1, j gradientStrength > copyImage.Pixels[i - 1, j].Gradient.Strength)) // i - 1, j image.Pixels[i, j].Gradient.Strength = 0; } else if (gradientDirection == GradientData.RoundGradientDirection.DEGREE_135) { int gradientStrength = copyImage.Pixels[i, j].Gradient.Strength; if (!(gradientStrength > copyImage.Pixels[i - 1, j - 1].Gradient.Strength && gradientStrength > copyImage.Pixels[i + 1, j + 1].Gradient.Strength)) image.Pixels[i, j].Gradient.Strength = 0; } } } catch (Exception exception) { throw exception; } }
/// <summary> /// Определяет границы серого изображения /// </summary> /// <param name="image">Серое изображение</param> public void Detect(GreyImage image) { try { if (image == null) throw new ArgumentNullException("Null image in Detect"); this.SmoothingFilter.Apply(image); _greySmoothedImage = (GreyImage)image.Copy(); this.EdgeDetectionFilter.Apply(image); SetGradientDirection(image); NonMaximaSuppression(image); DoubleTresholding(image); EdgeTrackingByHysteresis(image); SetEdgesColor(image); } catch (Exception exception) { throw exception; } }
/// <summary> /// Применение адаптивного фильтра Гаусса к серому изображению /// </summary> /// <param name="image">Серое изображение</param> private void ProcessImage(GreyImage image) { try { int imageHeight = image.Height - 2; int imageWidth = image.Width - 2; GreyImage copyImage = (GreyImage) image.Copy(); for (int i = 1; i < imageHeight; i++) for (int j = 1; j < imageWidth; j++) { double w1 = CalculateWeight(copyImage, i - 1, j - 1); double w2 = CalculateWeight(copyImage, i - 1, j); double w3 = CalculateWeight(copyImage, i - 1, j + 1); double w4 = CalculateWeight(copyImage, i, j - 1); double w5 = CalculateWeight(copyImage, i, j + 1); double w6 = CalculateWeight(copyImage, i + 1, j - 1); double w7 = CalculateWeight(copyImage, i + 1, j); double w8 = CalculateWeight(copyImage, i + 1, j + 1); double wCurrentPixel = CalculateWeight(copyImage, i, j); double N = w1 + w2 + w3 + w4 + w5 + w6 + w7 + w8 + wCurrentPixel; double newPixelValue = w1 * copyImage.Pixels[i - 1, j - 1].Color.Data + w2 * copyImage.Pixels[i - 1, j].Color.Data + w3 * copyImage.Pixels[i - 1, j + 1].Color.Data + w4 * copyImage.Pixels[i, j - 1].Color.Data + w5 * copyImage.Pixels[i, j + 1].Color.Data + w6 * copyImage.Pixels[i + 1, j - 1].Color.Data + w7 * copyImage.Pixels[i + 1, j].Color.Data + w8 * copyImage.Pixels[i + 1, j + 1].Color.Data + wCurrentPixel * copyImage.Pixels[i, j].Color.Data; if (N == 0.0) image.Pixels[i, j].Color.Data = (byte) ColorBase.MIN_COLOR_VALUE; else { int newColor = (int) (newPixelValue / N); if (newColor > ColorBase.MAX_COLOR_VALUE) newColor = ColorBase.MAX_COLOR_VALUE; if (newColor < ColorBase.MIN_COLOR_VALUE) newColor = ColorBase.MIN_COLOR_VALUE; image.Pixels[i, j].Color.Data = (byte)newColor; } } } catch (Exception exception) { throw exception; } }
/// <summary> /// Усиление градиентного изображения фильтром 3 на 3 /// </summary> /// <param name="image">Градиентное изображение </param> private void EnhanceGradientImage(GreyImage image) { try { int imageHeight = image.Height - 1; int imageWidth = image.Width - 1; GreyImage copyImage = (GreyImage)image.Copy(); for (int i = 1; i < imageHeight; i++) for (int j = 1; j < imageWidth; j++) image.Pixels[i, j].Color.Data = (byte) GetMaximumIntensityFromNeibours(copyImage, i, j); } catch (Exception exception) { throw exception; } }