Autokontrast und Autohelligkeit mit Emgu.CV und OpenCV in C#

Autokontrast und Autohelligkeit mit Emgu.CV und OpenCV in C#

Nachdem ich in OpenCV zunächst dachte, die Funktion EqualizeHist würde eine Anpassung Autokontrast/Autohelligkeit durchführen, habe ich mich doch gewundert, als ich festgestellt habe, daß diese Funktion Eingangs- und Ausgangsbild nichtlinear neu mappt, basierend auf den benutzen Indizes im Histogramm.

Ferner bietet OpenCV wohl diese Funktionalität (so wie gewünscht) nicht von Haus aus, diese läßt sich jedoch leicht nachprogrammieren.

Die Implementierung basiert komplett auf diesem einfachen Algorithmus, gefunden bei Stackoverflow.

Die Schritte:

  1. Berechne Histogramm
  2. Suche 5te und 95the Perzentil mithilfe einer akkumulierten Summe
  3. Berechne Faktor/Kontrast, um Histogramm auf 255 benutzte Werte zu skalieren
  4. Berechne Summand/Helligkeit, um Histogramm auf Bereich 0..255 zu ziehen
  5. Berechne Bild neu

Durch die Benutzung der Perzentil wird sichergestellt, daß einzelne Helligkeits-Ausreißer das Ergebnis nicht beeinflussen. So werden wir dann ca. 5% Pixel erhalten, die komplett weiß sowie komplett schwarz sind.

Das hier gezeigte Beispiel basiert auf einem Graubild, es läßt sich analog für RGB o. ä. Bilder verwenden, gemäß den unterstützen Formaten von OpenCV.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
  static Emgu.CV.Image<Emgu.CV.Structure.Gray, byte> AutoContrastBrightness(Emgu.CV.Image<Emgu.CV.Structure.Gray, byte> grayImage)
	{
		Emgu.CV.Image<Emgu.CV.Structure.Gray, byte> clonedGrayImage;
		clonedGrayImage = grayImage.Clone();
		var hist = new Emgu.CV.DenseHistogram(256, new Emgu.CV.Structure.RangeF(0.0f, 255.0f));
		// Histogram Computing
		hist.Calculate<Byte>(new Emgu.CV.Image<Emgu.CV.Structure.Gray, byte>[] { clonedGrayImage }, true, null);
		var mat = hist.MatND;
		float[] sum = new float[256];
		var myArr = mat.ManagedArray as float[];
		sum[0] = myArr[0];
		for (int i = 1; i < 256; ++i)
			sum[i] = sum[i - 1] + myArr[i];
 
		// find percentile
		var percentile = 0.05;
		var percentiledark = sum.Select((f, Index) => new { f = f, Index = Index }).Where(fi => fi.f > sum[255] * percentile).First().Index;
		var percentilebright = sum.Select((f, Index) => new { f = f, Index = Index }).Where(fi => fi.f > sum[255] * (1-percentile)).First().Index;
 
		// scaling == gain == contrast
		var scale = 255f / (percentilebright - percentiledark);
		if (scale == 0)
			scale = 1;
 
		// shift == offset == brightness
		var shift = (-(percentilebright + percentiledark) / 2 / scale); //+127);
 
		// recalculate image
		var newImage = clonedGrayImage.ConvertScale<byte>(scale, shift);
 
		return newImage;
	}

4 thoughts on “Autokontrast und Autohelligkeit mit Emgu.CV und OpenCV in C#

  1. I changed to:
    // Find percentile
    var percentile = 0.01 ; //0.5
    // Scaling == == gain contrast
    var scale = 22f / ( percentilebright – percentiledark ) ; //255

    It’s evening here, lights on, in the morning I don’t know what’s the result.

    thanks again!

    1. Thanks for all insightful comments. 🙂
      I remember from back then: this was not for giving „nice” results for ordinary photos.
      This was for maximizing the contrast/value range in a preprocessing for checker detection for distortion correction calibration.
      So you will always get a high value range in the output, which was good in my case but is not good for just about any ordinary photograph or image, where you will have to use some more advanced mechanism, like detecting what is in the foreground, faces, scenes, …

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.