2016-08-24 18 views
5

मैं कुछ दिनचर्या, लिखा है एक 3x3 गिरी का उपयोग कर एक ग्रेस्केल छवि को पैना करनेFFT कनवल्शन - 3x3 गिरी

-1 -1 -1 
-1 9 -1 
-1 -1 -1 

निम्नलिखित कोड गैर FFT (स्थानिक-डोमेन) घुमाव के मामले में अच्छी तरह से काम कर रहा है, लेकिन, एफएफटी-आधारित (आवृत्ति-डोमेन) संकल्प में काम नहीं कर रहा है।

आउटपुट छवि धुंधला लगती है।

मैं कई समस्याएं हैं:

(1) यह दिनचर्या वांछित परिणाम उत्पन्न करने में सक्षम नहीं किया जा रहा है। यह एप्लिकेशन को भी जमा करता है।

public static Bitmap ApplyWithPadding(Bitmap image, Bitmap mask) 
    { 
     if(image.PixelFormat == PixelFormat.Format8bppIndexed) 
     { 
      Bitmap imageClone = (Bitmap)image.Clone(); 
      Bitmap maskClone = (Bitmap)mask.Clone(); 

      ///////////////////////////////////////////////////////////////// 
      Complex[,] cPaddedLena = ImageDataConverter.ToComplex(imageClone); 
      Complex[,] cPaddedMask = ImageDataConverter.ToComplex(maskClone); 

      Complex[,] cConvolved = Convolution.Convolve(cPaddedLena, cPaddedMask); 

      return ImageDataConverter.ToBitmap(cConvolved); 
     } 
     else 
     { 
      throw new Exception("not a grascale"); 
     } 
    } 

(2) यह दिनचर्या अच्छा परिणाम देता है। लेकिन, नरक के रूप में धीमी है।

public static Bitmap Apply(Bitmap sourceBitmap) 
    { 
     Sharpen filter = new Sharpen(); 

     BitmapData sourceData = sourceBitmap.LockBits(new Rectangle(0, 0, 
           sourceBitmap.Width, sourceBitmap.Height), 
           ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); 

     byte[] pixelBuffer = new byte[sourceData.Stride * sourceData.Height]; 
     byte[] resultBuffer = new byte[sourceData.Stride * sourceData.Height]; 

     Marshal.Copy(sourceData.Scan0, pixelBuffer, 0, pixelBuffer.Length); 

     sourceBitmap.UnlockBits(sourceData); 

     double blue = 0.0; 
     double green = 0.0; 
     double red = 0.0; 

     int filterWidth = filter.FilterMatrix.GetLength(1); 
     int filterHeight = filter.FilterMatrix.GetLength(0); 

     int filterOffset = (filterWidth - 1)/2; 
     int calcOffset = 0; 

     int byteOffset = 0; 

     for (int offsetY = filterOffset; offsetY < sourceBitmap.Height - filterOffset; offsetY++) 
     { 
      for (int offsetX = filterOffset; offsetX < 
       sourceBitmap.Width - filterOffset; offsetX++) 
      { 
       blue = 0; 
       green = 0; 
       red = 0; 

       byteOffset = offsetY * 
          sourceData.Stride + 
          offsetX * 4; 

       for (int filterY = -filterOffset; 
        filterY <= filterOffset; filterY++) 
       { 
        for (int filterX = -filterOffset; 
         filterX <= filterOffset; filterX++) 
        { 

         calcOffset = byteOffset + 
            (filterX * 4) + 
            (filterY * sourceData.Stride); 

         blue += (double)(pixelBuffer[calcOffset]) * 
           filter.FilterMatrix[filterY + filterOffset, 
                filterX + filterOffset]; 

         green += (double)(pixelBuffer[calcOffset + 1]) * 
           filter.FilterMatrix[filterY + filterOffset, 
                filterX + filterOffset]; 

         red += (double)(pixelBuffer[calcOffset + 2]) * 
           filter.FilterMatrix[filterY + filterOffset, 
                filterX + filterOffset]; 
        } 
       } 

       blue = filter.Factor * blue + filter.Bias; 
       green = filter.Factor * green + filter.Bias; 
       red = filter.Factor * red + filter.Bias; 

       if (blue > 255) 
       { blue = 255; } 
       else if (blue < 0) 
       { blue = 0; } 

       if (green > 255) 
       { green = 255; } 
       else if (green < 0) 
       { green = 0; } 

       if (red > 255) 
       { red = 255; } 
       else if (red < 0) 
       { red = 0; } 

       resultBuffer[byteOffset] = (byte)(blue); 
       resultBuffer[byteOffset + 1] = (byte)(green); 
       resultBuffer[byteOffset + 2] = (byte)(red); 
       resultBuffer[byteOffset + 3] = 255; 
      } 
     } 

     Bitmap resultBitmap = new Bitmap(sourceBitmap.Width, sourceBitmap.Height); 

     BitmapData resultData = resultBitmap.LockBits(new Rectangle(0, 0, 
           resultBitmap.Width, resultBitmap.Height), 
           ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); 

     Marshal.Copy(resultBuffer, 0, resultData.Scan0, resultBuffer.Length); 
     resultBitmap.UnlockBits(resultData); 

     return resultBitmap; 
    } 

(3) निम्नलिखित मेरी जीयूआई कोड है। SharpenFilter.ApplyWithPadding() अगर मैं एक मुखौटा के रूप में छवि का उपयोग करता हूं तो ठीक से काम करता है। लेकिन, अगर मैं, 3 x 3 कर्नेल का उपयोग करता हूं, तो काम नहीं करता है।

string path = @"E:\lena.png"; 
    string path2 = @"E:\mask.png"; 

    Bitmap _inputImage; 
    Bitmap _maskImage; 

    private void LoadImages_Click(object sender, EventArgs e) 
    { 
     _inputImage = Grayscale.ToGrayscale(Bitmap.FromFile(path) as Bitmap); 

     /* 
     _maskImage = Grayscale.ToGrayscale(Bitmap.FromFile(path2) as Bitmap); 
     */ 

     SharpenFilter filter = new SharpenFilter(); 
     double[,] mask = new double[,] { { -1, -1, -1, }, 
             { -1, 9, -1, }, 
             { -1, -1, -1, }, }; 
     _maskImage = ImageDataConverter.ToBitmap(mask); 

     inputImagePictureBox.Image = _inputImage; 
     maskPictureBox.Image = _maskImage; 
    } 

    Bitmap _paddedImage; 
    Bitmap _paddedMask; 
    private void padButton_Click(object sender, EventArgs e) 
    { 
     Bitmap lena = Grayscale.ToGrayscale(_inputImage); 
     Bitmap mask = Grayscale.ToGrayscale(_maskImage); 

     ////Not working... 
     //int maxWidth = (int)Math.Max(lena.Width, mask.Width); 
     //int maxHeight = (int)Math.Max(lena.Height, mask.Height); 

     ////This is working correctly in case if I use a png image as a mask. 
     int maxWidth = (int)Tools.ToNextPow2(Convert.ToUInt32(lena.Width + mask.Width)); 
     int maxHeight = (int)Tools.ToNextPow2(Convert.ToUInt32(lena.Height + mask.Height)); 

     _paddedImage = ImagePadder.Pad(lena, maxWidth, maxHeight); 
     _paddedMask = ImagePadder.Pad(mask, maxWidth, maxHeight); 

     paddedImagePictureBox.Image = _paddedImage; 
     paddedMaskPictureBox.Image = _paddedMask; 
    } 

    private void filterButton_Click(object sender, EventArgs e) 
    { 
     // Not working properly. 
     // Freezes the application. 
     Bitmap sharp = SharpenFilter.ApplyWithPadding(_paddedImage, _paddedMask); 

     ////Works well. But, very slow. 
     //Bitmap sharp = SharpenFilter.Apply(_paddedImage); 

     filteredPictureBox.Image = sharp as Bitmap; 
    } 

आउटपुट:

enter image description here


स्रोत कोड:

enter image description here

  • यो आप पूरे समाधान को here in this link से डाउनलोड कर सकते हैं।
+0

हाय:

sharpened image

आसान दृश्य तुलना के लिए, यहाँ मूल छवि फिर से है निर्दिष्ट किया कि 'Convolution.Convolve (x, y) 'क्या करता है? किसी भी मामले में चारों ओर अंतरिक्ष में कनवॉल्यूशन एक गुणा है। तो यदि आप जटिल रूप से शब्द को गुणा करके cPaddedLena और cPaddedMask के चार प्रकार के परिवर्तन को बदलते हैं (उन्हें चौकोर स्थान में समान आयाम होने के लिए गद्देदार होना चाहिए) और उलटा चौराहे ऑपरेशन को बदल देगा –

उत्तर

4

मुख्य मुद्दा कर्नेल की व्याख्या के साथ एक हस्ताक्षरित बाइट मानों वाली छवि के रूप में प्रतीत होता है। नतीजतन -1 मूल्यों को प्रभावी ढंग से गिरी

255 255 255 
255 9 255 
255 255 255 

यह तुरंत "कनवल्शन कर्नेल" छवि में सफेद क्षेत्र से मनाया जा सकता है के साथ एक घुमाव के कंप्यूटिंग 255 करने के लिए परिवर्तित कर रहे हैं। परिणामी कर्नेल इस प्रकार एक कम-पास फ़िल्टर का होता है, जो एक धुंधला प्रभाव उत्पन्न करता है।

शायद इसे संभालने का सबसे अच्छा तरीका कर्नेल को छवि के बजाय हस्ताक्षरित मानों के मैट्रिक्स के रूप में पढ़ना होगा।

यदि आप अभी भी कर्नेल को छवि के रूप में संभालना पसंद करते हैं, तो आपको छवि को वापस हस्ताक्षरित मानों में कनवर्ट करना होगा।सबसे आसान तरीका मैं इस परिणाम को प्राप्त करने के बारे में सोच सकते ImageDataConverter.ToInteger(Bitmap) का एक संशोधित संस्करण बनाने के लिए किया जाएगा जहां मूल्यों में बाइट्स नक्शा:

public static Complex[,] Unwrap(Bitmap bitmap) 
{ 
    int Width = bitmap.Width; 
    int Height = bitmap.Height; 

    Complex[,] array2D = new Complex[bitmap.Width, bitmap.Height]; 
    ... 

     else// If there is only one channel: 
     { 
      iii = (int)(*address); 
      if (iii >= 128) 
      { 
      iii -= 256; 
      } 
     } 
     Complex tempComp = new Complex((double)iii, 0.0); 
     array2D[x, y] = tempComp; 

फिर आप के साथ SharpenFilter.ApplyWithPadding में अपनी छवि बदलने में सक्षम होगा:

Complex[,] cPaddedMask = ImageDataConverter.Unwrap(maskClone); 

यह तो आप निम्नलिखित परिणाम देना चाहिए:

Dynamic scaling lena

Whil ई यह छवि की तीखेपन में सुधार करता है, आपको तुरंत ध्यान देना चाहिए कि छवि मूल की तुलना में बहुत गहरा है। यह Convolution.Rescale फ़ंक्शन के कारण है जो छवि को न्यूनतम और अधिकतम मान के अनुसार गतिशील रूप से पुन: सहेजता है। छवि को अधिकतम गतिशील रेंज के साथ दिखाने के लिए सुविधाजनक हो सकता है, लेकिन परिणामस्वरूप मानक संकल्प की तुलना में एक अलग समग्र स्केलिंग हो सकती है।

//Rescale values between 0 and 255. 
    private static void Rescale(Complex[,] convolve) 
    { 
     int imageWidth = convolve.GetLength(0); 
     int imageHeight = convolve.GetLength(1); 

     double scale = imageWidth * imageHeight; 

     for (int j = 0; j < imageHeight; j++) 
     { 
      for (int i = 0; i < imageWidth; i++) 
      { 
       double re = Math.Max(0, Math.Min(convolve[i, j].Real * scale, 255.0)); 
       double im = Math.Max(0, Math.Min(convolve[i, j].Imaginary * scale, 255.0)); 
       convolve[i, j] = new Complex(re, im); 
      } 
     } 
    } 

यह तो आप एक अधिक उपयुक्त चमक स्तर के साथ एक छवि देना चाहिए:

Standard scaling

इस मानक स्केलिंग (अपने FFT कार्यान्वयन की स्केलिंग के आधार पर) प्राप्त करने के लिए, आप निम्न कार्यान्वयन इस्तेमाल कर सकते हैं

आखिरकार, एक फ़िल्टरिंग ऑपरेशन के लिए आम तौर पर परिणाम मूल छवि आकार से मिलान करने की अपेक्षा करता है (एक संकल्प के विपरीत जिसमें पूंछ शामिल हैं)। साथ SharpenFilter.ApplyWithPadding में परिणाम फसल:

... 
// -3 terms are due to kernel size 
// +5 vertical offset term is due to vertical reflection & offset in SetPixel 
Rectangle rect = new Rectangle((cPaddedLena.GetLength(0)/2 - 3)/2, 
           (cPaddedLena.GetLength(1)/2 - 3)/2 + 5, 
           cPaddedLena.GetLength(0)/2, 
           cPaddedLena.GetLength(1)/2); 
return ImageDataConverter.ToBitmap(cConvolved).Clone(rect, PixelFormat.Format8bppIndexed); 

आप देना चाहिए: कर सकते हैं

original image

संबंधित मुद्दे