F #, aumentando el contraste de la imagen alineando los histogramas

La operación de alineación del histograma (aumento del contraste) se usa a menudo para aumentar la calidad de la imagen. En el marco de este artículo, se considerará el concepto de un histograma , la teoría de un algoritmo para su alineación y ejemplos prácticos del funcionamiento de este algoritmo. Para facilitar el procesamiento de imágenes, utilizaremos la biblioteca OpenCV . Además, haremos un análisis comparativo de los resultados de nuestro algoritmo y el algoritmo que ya está integrado en OpenCV .



El histograma es una función h (x) , que devuelve el número total de píxeles cuyo brillo es igual a x .


El histograma h de la imagen de medios tonos I viene dado por

h(metro)=El |(r,C)El |yo(r,C)=metroEl |


, donde m corresponde a los intervalos de valores de brillo

A continuación se muestra el pseudocódigo para calcular el histograma.


//   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;
        };
}

Visualmente, el histograma es un rectángulo, cuyo ancho es igual al valor máximo posible del brillo de un punto en la imagen original. Para las imágenes en escala de grises, trabajaremos con un rango de brillo de puntos de 0 a 255, lo que significa que el ancho del histograma será 256. La altura del histograma puede ser cualquiera, pero para mayor claridad, trabajaremos con histogramas rectangulares.


Desde el punto de vista del programador, un histograma es una matriz unidimensional de dimensión 256 (en nuestro caso), donde cada elemento de la matriz almacena el número total de puntos con el brillo correspondiente. A continuación se muestra un ejemplo visual de dicho histograma.


Figura 1. Visualización gráfica del histograma 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


CreX(X)=h(0 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)=rotunortere(CreF(X)-CreFmetroyonortepagsyoXmils-1255)



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.







El autor del artículo está lejos de ser original y no inventó nada nuevo, presentando al público otra historia sobre cómo se implementa el algoritmo de alineación del histograma y por qué es necesario. El objetivo principal del artículo no era solo hablar sobre el algoritmo, sino también dar ejemplos prácticos específicos y códigos fuente que puede copiar y verificar usted mismo, y posiblemente experimentar. Por supuesto, el algoritmo de histograma no es el único utilizado para filtrar imágenes. Pero este es el tema de otros temas.


All Articles