F #, Erhöhen des Bildkontrasts durch Ausrichten der Histogramme

Die Histogrammausrichtungsoperation (zunehmender Kontrast) wird hĂ€ufig verwendet, um die BildqualitĂ€t zu erhöhen. Im Rahmen dieses Artikels werden das Konzept eines Histogramms , die Theorie eines Algorithmus fĂŒr seine Ausrichtung und praktische Beispiele fĂŒr die Funktionsweise dieses Algorithmus betrachtet . Um die Bildverarbeitung zu vereinfachen, verwenden wir die OpenCV-Bibliothek . Außerdem werden wir eine vergleichende Analyse der Ergebnisse unseres Algorithmus und des Algorithmus durchfĂŒhren, der bereits in OpenCV integriert ist .



Das Histogramm ist eine Funktion h (x) , die die Gesamtzahl der Pixel zurĂŒckgibt, deren Helligkeit gleich x ist .


Das Histogramm h des Halbtonbildes I ist gegeben durch

h(m)=|(r,c)|ich(r,c)=m|


wobei m den Intervallen der Helligkeitswerte entspricht

Unten finden Sie den Pseudocode zur Berechnung des Histogramms.


//   H    I.

procedure histogram(I,H);
{
    //     .
    for i := 0 to MaxVal
        H[i] := 0;

    //   .
    for L := 0 to MaxRow
        for P := 0 to MaxCol {
            grayval := I[r,c];
            H[grayval] := H[grayval] + 1;
        };
}

Visuell ist das Histogramm ein Rechteck, dessen Breite dem maximal möglichen Wert der Helligkeit eines Punkts im Originalbild entspricht. FĂŒr Graustufenbilder arbeiten wir mit einem Helligkeitsbereich von Punkten von 0 bis 255, was bedeutet, dass die Breite des Histogramms 256 betrĂ€gt. Die Höhe des Histogramms kann beliebig sein, aber aus GrĂŒnden der Klarheit werden wir mit rechteckigen Histogrammen arbeiten.


, — 256 ( ), . .


1. h(x)



. — cdf(x) .


, OpenCV , , . , , . F# OpenCVSharp4.


, Visual Studio, . , MacOS, , "runtimes/osx-x64/native/libOpenCvSharpExtern.dylib" , .
Unable to load shared library 'OpenCvSharpExtern' or one of its dependencies


,


open OpenCvSharp
open Microsoft.FSharp.NativeInterop

// mat -   Mat  OpenCV
let getHistogram (mat: Mat) =
    //   
    let hx = Array.zeroCreate<int> 256
    //  
    mat.ForEachAsByte(fun value _ ->
                           let v = int (NativePtr.get value 0)
                           hx.[v] <- hx.[v] + 1)
    //  
    hx

, . X


cdx(x)=h(0)+h(1)+...+h(x)


, X. 1 ( ).


, cdf(x)


let getCdx hx = // hx - 
   //   
   hx |> Array.mapi (fun x _ -> if x > 0 then hx.[0..(x-1)] |> Array.sum else 0)


1 , . ( ), . , , .


2.


2.



, .


:


f(x)=rÖund(cdf(x)- -cdfmichnpichxels- -1⋅255)



cdf(x) — X
cdf_min — ,
pixels —
255 — . 255
round —


F# :


//  cdf_min
let cdxMin = cdx |> Array.filter (fun v -> v > 0) |> Array.min
//      
let totalPixels = src.Rows * src.Cols // src -   Mat   

for y in 0..src.Rows do
    for x in 0..src.Cols do
        //     
        let s = int(src.At<byte>(y, x))
        //     
        let fx = (float(cdx.[s]) - float(cdxMin))/(float(totalPixels - 1))*255.
        //    
        equalizeImage.Circle(x, y, 1, new Scalar(double(fx)))

, . . , OpenCV .


// Learn more about F# at http://fsharp.org
open OpenCvSharp
open Microsoft.FSharp.NativeInterop

//     
let getHistogram (mat: Mat) =
    let hx = Array.zeroCreate<int> 256
    mat.ForEachAsByte(fun value _ ->
                           let v = int (NativePtr.get value 0)
                           hx.[v] <- hx.[v] + 1)
    hx

//      
let getCdx hx =
    hx |> Array.mapi (fun x _ -> if x > 0 then hx.[0..(x-1)] |> Array.sum else 0)

//     
let drawHistogramAndCdx hx cdx (mat: Mat) =
    let histoWidth = 256
    let histoHeight = 256

    //     
    let cdxMax = cdx |> Array.max
    //      ( )
    //    
    let cdxK = float(histoHeight)/float(cdxMax)

    let histMax = hx |> Array.max
    let histK = float(histoHeight)/float(histMax)

    let histMat = new Mat(histoWidth, histoHeight, MatType.CV_8UC4)
    hx
    |> Array.iteri (fun x v ->
                        let histDy = int(float(v)*histK)
                        let cdxDy = int(float(cdx.[x])*cdxK)
                        //   h(x)
                        mat.Line(x, histoHeight-1, x, histoHeight-1-histDy, Scalar.White)
                        //    cdx(x)
                        mat.Circle(x, histoHeight-cdxDy, 1, Scalar.Blue))

[<EntryPoint>]
let main argv =

    let histoWidth = 256
    let histoHeight = 256

    let src = Cv2.ImRead("cat.jpg", ImreadModes.Grayscale)
    let equalizeImage = new Mat(src.Rows, src.Cols, MatType.CV_8UC1)

    // calculate histogram h(x)
    let hx = getHistogram src

    // calculate cdf(x) = h(0) + h(1) + .. + h(x)
    let cdx = getCdx hx

    // draw histogram
    let histMat = new Mat(histoWidth, histoHeight, MatType.CV_8UC4)
    drawHistogramAndCdx hx cdx histMat

    // equalize the histogram
    let cdxMin = cdx |> Array.filter (fun v -> v > 0) |> Array.min
    let totalPixels = src.Rows * src.Cols

    for y in 0..src.Rows do
        for x in 0..src.Cols do
            let s = int(src.At<byte>(y, x))
            let fx = (float(cdx.[s]) - float(cdxMin))/(float(totalPixels - 1))*255.
            //equalizeImage.Set<Scalar>(y, x, new Scalar(double(fx)))
            equalizeImage.Circle(x, y, 1, new Scalar(double(fx)))

    // calculate equalize histogram
    let hx2 = getHistogram equalizeImage
    let cdx2 = getCdx hx2

    let histMat2 = new Mat(histoWidth, histoHeight, MatType.CV_8UC4)
    drawHistogramAndCdx hx2 cdx2 histMat2

    // opencv equalize histogram
    let opencCVImage = new Mat(src.Rows, src.Cols, MatType.CV_8UC1)
    let in1 = InputArray.Create(src)
    let in2 = OutputArray.Create(opencCVImage)

    Cv2.EqualizeHist(in1, in2)

    // get opencv histogram
    let hx3 = getHistogram opencCVImage
    let cdx3 = getCdx hx3

    let histMat3 = new Mat(histoWidth, histoHeight, MatType.CV_8UC4)
    drawHistogramAndCdx hx3 cdx2 histMat3

    // show results
    use w1 = new Window("original image", src)
    use w2 = new Window("original histogram", histMat)

    use w3 = new Window("custom equalize image", equalizeImage)
    use w4 = new Window("custom equalize histogram", histMat2)

    use w5 = new Window("opencv equalize image", opencCVImage)
    use w6 = new Window("opencv equalize histogram", histMat3)

    Cv2.WaitKey() |> ignore

    0 // return an integer exit code


3.


, , OpenCV.


( ), — , — OpenCV.







Der Autor des Artikels ist alles andere als originell und hat nichts Neues erfunden. Er prĂ€sentierte der Öffentlichkeit eine andere Geschichte darĂŒber, wie der Histogramm-Ausrichtungsalgorithmus implementiert wird und warum er benötigt wird. Der Hauptzweck des Artikels bestand nicht nur darin, ĂŒber den Algorithmus zu sprechen, sondern auch spezifische praktische Beispiele und Quellcodes anzugeben, die Sie selbst kopieren und ĂŒberprĂŒfen und möglicherweise experimentieren können. NatĂŒrlich ist der Histogrammalgorithmus nicht der einzige, der zum Filtern von Bildern verwendet wird. Dies ist jedoch das Thema anderer Themen.


All Articles