2013-03-12 15 views
7

में बहुत छोटे अंतर का पता लगाने वाले ऑटोफोकस दिनचर्या मैं माइक्रोमैटर पैमाने पर स्थिति के लिए एक ऑटोफोकस दिनचर्या विकसित कर रहा हूं, इसलिए मुझे छवियों के बीच फोकस/धुंध में बहुत कम अंतर खोजने की आवश्यकता है।ब्लूटूथ

0 µm off50 µm off

  Perfect focus   |   50 µm off 

उपरोक्त दो के बेहतर ध्यान केंद्रित छवि खोजना एक समस्या नहीं है: सौभाग्य से, छवि पैटर्न हमेशा एक जैसी रहेगी (इन मूल 2 सांसद छवियों की 256x256 केंद्र फसलें हैं) , मुझे लगता है कि अधिकांश एल्गोरिदम करेंगे। दो छवियों है कि खोजने के लिए करीब है और इष्टतम फोकस के करीब कदम है

5 µm off10 µm off

  5 µm off   |   10 µm off 

एक वैकल्पिक: लेकिन मैं वास्तव में ध्यान केंद्रित करने में बहुत कम अंतर के साथ चित्रों की तुलना करने के लिए, नीचे दिए गए ऐसे आवश्यकता फोकस प्लेन के विपरीत किनारों पर धुंध की एक ही मात्रा। उदाहरण के लिए, कोई -50 माइक्रोन से एक छवि को सहेज सकता है और फिर +50 माइक्रोन के आसपास एक छवि को खोजने का प्रयास करें जहां धुंध बराबर है। आइए कहें कि छवि +58 माइक्रोन पर मिली थी, फिर फोकस प्लेन को +4 माइक्रोन पर रखा जाना चाहिए।

उपयुक्त एल्गोरिदम के लिए कोई विचार?

+1

जब आप बुनियादी एल्गोरिदम कोशिश क्या होता है के लिए काम करेंगे? क्या बहुत कम सिग्नल-टू-शोर है? –

+0

ठीक है, मैंने अभी माना है कि एक मूल एल्गोरिदम 0, 5 और 10 माइक्रोन छवियों के बीच किसी भी वैध अंतर का पता नहीं लगाएगा। लेकिन मैंने अभी कुछ कोशिश की और वास्तव में काफी आशाजनक परिणाम मिल गए। मैं सिर्फ 1 माइक्रोन के अलावा और अधिक छवियां प्राप्त करूंगा और देख सकता हूं कि परिणाम अभी भी सतर्क हैं या नहीं। – Anlo

उत्तर

10

आश्चर्य की बात है कि, इस समस्या पर वास्तव में बहुत सरल ऑटोफोकस एल्गोरिदम वास्तव में काफी अच्छा प्रदर्शन करते हैं। मैंने लियू, वांग & सूर्य द्वारा पेपर Dynamic evaluation of autofocusing for automated microscopic analysis of blood smear and pap smear में उल्लिखित 16 एल्गोरिदम में से 11 को कार्यान्वित किया। चूंकि मुझे थ्रेसहोल्ड मानों को सेट करने के लिए अनुशंसाएं ढूंढने में परेशानी थी, इसलिए मैंने थ्रेसहोल्ड के बिना कुछ प्रकार भी जोड़े। मैंने SO पर यहां एक सरल लेकिन चालाक सुझाव भी जोड़ा: जेपीईजी संकुचित छवियों के फ़ाइल आकार की तुलना करें (बड़ा आकार = अधिक विस्तार = बेहतर फोकस)। 2 सुक्ष्ममापी फोकस दूरी के अंतराल, कुल रेंज ± 20 सुक्ष्ममापी पर

  • सहेजें 21 छवियों:

    मेरे ऑटोफोकस दिनचर्या निम्नलिखित है।

  • प्रत्येक छवि के फ़ोकस मूल्य की गणना करें।
  • परिणाम दूसरी डिग्री बहुपद के लिए फ़िट करें।
  • उस स्थिति को खोजें जो बहुपद का अधिकतम मूल्य देता है।

हिस्टोग्राम रेंज को छोड़कर सभी एल्गोरिदम अच्छे परिणाम दिए। कुछ एल्गोरिदम थोड़ा संशोधित होते हैं, उदाहरण के लिए वे X & वाई दिशाओं में चमक अंतर का उपयोग करते हैं। मुझे फोकस स्थिति पर न्यूनतम की बजाय अधिकतम प्राप्त करने के लिए StdevBasedCorrelation, Entropy, ThresholdedContent, ImagePower और ThresholdedImagePower एल्गोरिदम का संकेत भी बदलना पड़ा। एल्गोरिदम 24 बिट ग्रेस्केल छवि की अपेक्षा करते हैं जहां आर = जी = बी। यदि रंगीन छवि पर उपयोग किया जाता है, तो केवल नीले चैनल की गणना की जाएगी (पाठ्यक्रम की आसानी से सही)।

  • स्थिर फोकस स्थिति
  • बड़े नकारात्मक x²:

    इष्टतम सीमा मूल्यों एल्गोरिदम सीमा के साथ 0 महत्व देता है, 8 से 24 आदि 255 से ऊपर चल रहा है, 16, और के लिए सबसे अच्छा मूल्य का चयन करके मिला था गुणांक बहुपद फिट से

  • वर्गों का
  • कम अवशिष्ट राशि फोकस की स्थिति में एक संकीर्ण चोटी में जिसके परिणामस्वरूप

यह दिलचस्प है ध्यान दें कि ThresholdedSq uaredGredient और ThresholdedBrennerGradient एल्गोरिदम में फोकस स्थिति, x² गुणांक और वर्गों के अवशिष्ट योग की लगभग समतल रेखा होती है। वे दहलीज मूल्य में परिवर्तन के लिए बहुत असंवेदनशील हैं।

एल्गोरिदम के कार्यान्वयन:

public unsafe List<Result> CalculateFocusValues(string filename) 
{ 
    using(Bitmap bmp = new Bitmap(filename)) 
    { 
    int width = bmp.Width; 
    int height = bmp.Height; 
    int bpp = Bitmap.GetPixelFormatSize(bmp.PixelFormat)/8; 
    BitmapData data = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, bmp.PixelFormat); 

    long sum = 0, squaredSum = 0; 
    int[] histogram = new int[256]; 

    const int absoluteGradientThreshold = 148; 
    long absoluteGradientSum = 0; 
    long thresholdedAbsoluteGradientSum = 0; 

    const int squaredGradientThreshold = 64; 
    long squaredGradientSum = 0; 
    long thresholdedSquaredGradientSum = 0; 

    const int brennerGradientThreshold = 184; 
    long brennerGradientSum = 0; 
    long thresholdedBrennerGradientSum = 0; 

    long autocorrelationSum1 = 0; 
    long autocorrelationSum2 = 0; 

    const int contentThreshold = 35; 
    long thresholdedContentSum = 0; 

    const int pixelCountThreshold = 76; 
    long thresholdedPixelCountSum = 0; 

    const int imagePowerThreshold = 40; 
    long imagePowerSum = 0; 
    long thresholdedImagePowerSum = 0; 

    for(int row = 0; row < height - 1; row++) 
    { 
     for(int col = 0; col < width - 1; col++) 
     { 
     int current = *((byte *) (data.Scan0 + (row + 0) * data.Stride + (col + 0) * bpp)); 
     int col1 = *((byte *) (data.Scan0 + (row + 0) * data.Stride + (col + 1) * bpp)); 
     int row1 = *((byte *) (data.Scan0 + (row + 1) * data.Stride + (col + 0) * bpp)); 

     int squared = current * current; 
     sum += current; 
     squaredSum += squared; 
     histogram[current]++; 

     int colDiff1 = col1 - current; 
     int rowDiff1 = row1 - current; 

     int absoluteGradient = Math.Abs(colDiff1) + Math.Abs(rowDiff1); 
     absoluteGradientSum += absoluteGradient; 
     if(absoluteGradient >= absoluteGradientThreshold) 
      thresholdedAbsoluteGradientSum += absoluteGradient; 

     int squaredGradient = colDiff1 * colDiff1 + rowDiff1 * rowDiff1; 
     squaredGradientSum += squaredGradient; 
     if(squaredGradient >= squaredGradientThreshold) 
      thresholdedSquaredGradientSum += squaredGradient; 

     if(row < bmp.Height - 2 && col < bmp.Width - 2) 
     { 
      int col2 = *((byte *) (data.Scan0 + (row + 0) * data.Stride + (col + 2) * bpp)); 
      int row2 = *((byte *) (data.Scan0 + (row + 2) * data.Stride + (col + 0) * bpp)); 

      int colDiff2 = col2 - current; 
      int rowDiff2 = row2 - current; 
      int brennerGradient = colDiff2 * colDiff2 + rowDiff2 * rowDiff2; 
      brennerGradientSum += brennerGradient; 
      if(brennerGradient >= brennerGradientThreshold) 
      thresholdedBrennerGradientSum += brennerGradient; 

      autocorrelationSum1 += current * col1 + current * row1; 
      autocorrelationSum2 += current * col2 + current * row2; 
     } 

     if(current >= contentThreshold) 
      thresholdedContentSum += current; 
     if(current <= pixelCountThreshold) 
      thresholdedPixelCountSum++; 

     imagePowerSum += squared; 
     if(current >= imagePowerThreshold) 
      thresholdedImagePowerSum += current * current; 
     } 
    } 
    bmp.UnlockBits(data); 

    int pixels = width * height; 
    double mean = (double) sum/pixels; 
    double meanDeviationSquared = (double) squaredSum/pixels; 

    int rangeMin = 0; 
    while(histogram[rangeMin] == 0) 
     rangeMin++; 
    int rangeMax = histogram.Length - 1; 
    while(histogram[rangeMax] == 0) 
     rangeMax--; 

    double entropy = 0.0; 
    double log2 = Math.Log(2); 
    for(int i = rangeMin; i <= rangeMax; i++) 
    { 
     if(histogram[i] > 0) 
     { 
     double p = (double) histogram[i]/pixels; 
     entropy -= p * Math.Log(p)/log2; 
     } 
    } 

    return new List<Result>() 
    { 
     new Result("AbsoluteGradient",   absoluteGradientSum), 
     new Result("ThresholdedAbsoluteGradient", thresholdedAbsoluteGradientSum), 
     new Result("SquaredGradient",    squaredGradientSum), 
     new Result("ThresholdedSquaredGradient", thresholdedSquaredGradientSum), 
     new Result("BrennerGradient",    brennerGradientSum), 
     new Result("ThresholdedBrennerGradient", thresholdedBrennerGradientSum), 
     new Result("Variance",     meanDeviationSquared - mean * mean), 
     new Result("Autocorrelation",    autocorrelationSum1 - autocorrelationSum2), 
     new Result("StdevBasedCorrelation",  -(autocorrelationSum1 - pixels * mean * mean)), 
     new Result("Range",      rangeMax - rangeMin), 
     new Result("Entropy",      -entropy), 
     new Result("ThresholdedContent",   -thresholdedContentSum), 
     new Result("ThresholdedPixelCount",  thresholdedPixelCountSum), 
     new Result("ImagePower",     -imagePowerSum), 
     new Result("ThresholdedImagePower",  -thresholdedImagePowerSum), 
     new Result("JpegSize",     new FileInfo(filename).Length), 
    }; 
    } 
} 

public class Result 
{ 
    public string Algorithm { get; private set; } 
    public double Value  { get; private set; } 

    public Result(string algorithm, double value) 
    { 
    Algorithm = algorithm; 
    Value  = value; 
    } 
} 

साजिश और विभिन्न एल्गोरिदम वे 0 और 1 (scaled = (value - min)/(max - min)) मान के मध्य बढ़ाया गया का ध्यान केंद्रित मूल्यों की तुलना करने में सक्षम होने के लिए।

± 20 सुक्ष्ममापी की एक श्रृंखला के लिए सभी एल्गोरिदम के प्लॉट:

:

±20 µm

0 µm20 µm

   0 µm    |    20 µm 

हालात ± 50 सुक्ष्ममापी की एक श्रृंखला के लिए काफी समान दिखाई ±50 µm

0 µm50 µm

   0 µm    |    50 µm 

± 500 की एक सीमा सुक्ष्ममापी बातें और दिलचस्प हो जाता का उपयोग करते समय। चार एल्गोरिदम चौथे डिग्री बहुपद आकार का प्रदर्शन करते हैं, और अन्य गॉसियन कार्यों की तरह दिखने लगते हैं। इसके अलावा, हिस्टोग्राम रेंज एल्गोरिदम छोटी श्रेणियों के मुकाबले बेहतर प्रदर्शन करना शुरू कर देता है।

±500 µm

0 µm500 µm

   0 µm    |    500 µm 

कुल मिलाकर मैं काफी प्रदर्शन और इन सरल एल्गोरिदम की निरंतरता से प्रभावित हूँ। नग्न आंखों के साथ, यह कहना मुश्किल है कि 50 माइक्रोन छवि भी फोकस से बाहर है लेकिन एल्गोरिदम में कुछ माइक्रोन अलग छवियों की तुलना में कोई समस्या नहीं है।

+0

हाय, मुझे पता है कि यह एक पुराना सवाल है, लेकिन मैं एक बहुत ही समान समस्या पर काम कर रहा हूं, इसलिए मैं उम्मीद कर रहा था कि आप इस बिंदु पर विस्तार कर सकते हैं "परिणाम को दूसरी डिग्री बहुपद में फ़िट करें।" – NindzAI

+0

हाय निंडज़एएल, कृपया मेरा अतिरिक्त उत्तर देखें (http://stackoverflow.com/a/17758994/306074) – Anlo

+0

@Anlo मुझे पता है कि यह एक बहुत पुराना सवाल है, लेकिन शायद आप भी बहुत ही सरल जेपीईजी आकार आधारित एल्गोरिदम का उपयोग कर सकते हैं नासा जिज्ञासा मंगल रोवर, मेरा जवाब देखें http://stackoverflow.com/a/32951113/15485 –

3

मूल जवाब पर NindzAl की टिप्पणी करने के लिए एक अतिरिक्त जवाब:

मैं Extreme Optimization लाइब्रेरी का उपयोग एक दूसरे की डिग्री बहुपद के तीखेपन मूल्यों के अनुरूप हों। अधिकतम तीखेपन की दूरी को बहुपद के पहले व्युत्पन्न का उपयोग करके निकाला जाता है।

चरम अनुकूलन लाइब्रेरी एक एकल देव लाइसेंस के लिए 999 अमेरिकी डॉलर खर्च करती है, लेकिन मुझे यकीन है कि ओपन सोर्स गणित पुस्तकालय हैं जो फिटिंग को भी कर सकते हैं।

// Distances (in µm) where the images were saved 
double[] distance = new double[] 
{ 
    -50, 
    -40, 
    -30, 
    -20, 
    -10, 
    0, 
    +10, 
    +20, 
    +30, 
    +40, 
    +50, 
}; 

// Sharpness value of each image, as returned by CalculateFocusValues() 
double[] sharpness = new double[] 
{ 
    3960.9, 
    4065.5, 
    4173.0, 
    4256.1, 
    4317.6, 
    4345.4, 
    4339.9, 
    4301.4, 
    4230.0, 
    4131.1, 
    4035.0, 
}; 

// Fit data to y = ax² + bx + c (second degree polynomial) using the Extreme Optimization library 
const int SecondDegreePolynomial = 2; 
Extreme.Mathematics.Curves.LinearCurveFitter fitter = new Extreme.Mathematics.Curves.LinearCurveFitter(); 
fitter.Curve = new Extreme.Mathematics.Curves.Polynomial(SecondDegreePolynomial); 
fitter.XValues = new Extreme.Mathematics.LinearAlgebra.GeneralVector(distance, true); 
fitter.YValues = new Extreme.Mathematics.LinearAlgebra.GeneralVector(sharpness, true); 
fitter.Fit(); 

// Find distance of maximum sharpness using the first derivative of the polynomial 
// Using the sample data above, the focus point is located at distance +2.979 µm 
double focusPoint = fitter.Curve.GetDerivative().FindRoots().First(); 
0

मुफ्त पुस्तकालय का सवाल है, Math.Net उस उद्देश्य