문제

I'm doing some image processing and ran in to an exception.

Let me explain the logic process;

  • Resize the image to to a smaller size
  • Turn it grayscale
  • Threshold the image
  • Save it for use later on.

When you threshold the image, the constructor can take an int that sets the intensity of the filter. The best way I've found to get this "magic number" is to use a method called GetOtsuThreshold. It uses unsafe code but works well. However, something strange happens when you call that method. After you call the otsu method, it causes the Aforge...Threshold.ApplyInPlace() method to throw a Parameter is not valid exception. If you don't call it (When the code is commented out) the whole thing runs just fine though.

Wot's the deal?

EDIT: Found the problem; You must put a new a new image into the otsu method because it disposes of the image!!

using System;
using System.Drawing;
using System.Drawing.Imaging;
using AForge.Imaging.Filters;

namespace Puma.Ocr.Tests
{
    class FormatImage
    {
        public static Bitmap _FullImageOfCoin;

        public FormatImage(string path)
        {
            _FullImageOfCoin = ScaleImage(new Bitmap(path), 2000, 2000);

            GrayscaleImage();

            ThresholdImage();

        }

        private void GrayscaleImage()
        {
            Grayscale filter = new Grayscale(0.2125, 0.7154, 0.0721);
            // apply the filter
            _FullImageOfCoin = filter.Apply(_FullImageOfCoin);
        }

        private void ThresholdImage()
        {
            //Causes the exception
            Threshold threshold = new Threshold(getOtsuThreshold(_FullImageOfCoin));

            //Runs fine
            //Threshold threshold = new Threshold();

            threshold.ApplyInPlace(_FullImageOfCoin);

            _FullImageOfCoin.Save(@"C:\users\school\desktop\thresholded.bmp");
        }

        public static Bitmap ScaleImage(Bitmap image, int maxWidth, int maxHeight)
        {
            var ratioX = (double)maxWidth / image.Width;
            var ratioY = (double)maxHeight / image.Height;
            var ratio = Math.Min(ratioX, ratioY);

            var newWidth = (int)(image.Width * ratio);
            var newHeight = (int)(image.Height * ratio);

            var newImage = new Bitmap(newWidth, newHeight);
            Graphics.FromImage(newImage).DrawImage(image, 0, 0, newWidth, newHeight);
            return newImage;
        }

        public int getOtsuThreshold(Bitmap bmp)
        {
            byte t = 0;
            float[] vet = new float[256];
            int[] hist = new int[256];
            vet.Initialize();

            float p1, p2, p12;
            int k;

            BitmapData bmData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height),
                                             ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
            unsafe
            {
                byte* p = (byte*)(void*)bmData.Scan0.ToPointer();

                getHistogram(p, bmp.Width, bmp.Height, bmData.Stride, hist);


                for (k = 1; k != 255; k++)
                {
                    p1 = Px(0, k, hist);
                    p2 = Px(k + 1, 255, hist);
                    p12 = p1 * p2;
                    if (p12 == 0)
                        p12 = 1;
                    float diff = (Mx(0, k, hist) * p2) - (Mx(k + 1, 255, hist) * p1);
                    vet[k] = (float)diff * diff / p12;

                }
            }
            bmp.UnlockBits(bmData);

            t = (byte)findMax(vet, 256);

            bmp.Dispose();

            return t;
        }

        private unsafe void getHistogram(byte* p, int w, int h, int ws, int[] hist)
        {
            hist.Initialize();
            for (int i = 0; i < h; i++)
            {
                for (int j = 0; j < w * 3; j += 3)
                {
                    int index = i * ws + j;
                    hist[p[index]]++;
                }
            }
        }

        private int findMax(float[] vec, int n)
        {
            float maxVec = 0;
            int idx = 0;
            int i;

            for (i = 1; i <= n - 1; i++)
            {
                if (vec[i] > maxVec)
                {
                    maxVec = vec[i];
                    idx = i;
                }
            }
            return idx;
        }

        private float Px(int init, int end, int[] hist)
        {
            int sum = 0;
            int i;
            for (i = init; i <= end; i++)
                sum += hist[i];

            return (float)sum;
        }

        // function is used to compute the mean values in the equation (mu)
        private float Mx(int init, int end, int[] hist)
        {
            int sum = 0;
            int i;
            for (i = init; i <= end; i++)
                sum += i * hist[i];

            return (float)sum;
        }
    }
}
도움이 되었습니까?

해결책 2

Alright, found the answer. By putting the _Fullimage of coin into the otsu method it stripped the variable of all it properties. I don't know how, but by putting a new Bitmap into the otsu method it fixed the problem.

다른 팁

A few ideas:

Since the filter can be applied as to 8 bpp and to 16 bpp images, the ThresholdValue value should be set appropriately to the pixel format. In the case of 8 bpp images the threshold value is in the [0, 255] range, but in the case of 16 bpp images the threshold value is in the [0, 65535] range.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top