首頁  >  文章  >  後端開發  >  高斯模糊實作會產生奇怪的輸出

高斯模糊實作會產生奇怪的輸出

WBOY
WBOY轉載
2024-02-11 09:20:081246瀏覽

高斯模糊實作會產生奇怪的輸出

php小編魚仔指出,高斯模糊是一種常用的影像處理技術,可以使影像變得模糊,常用於美化照片或實現特效。然而,如果不正確地實現高斯模糊演算法,可能會產生奇怪的輸出。這可能包括影像失真、邊緣模糊或色彩偏移等問題。因此,在使用高斯模糊技術時,必須注意演算法的正確實現,以確保獲得預期的輸出效果。

問題內容

我正在嘗試在 golang image.image 物件上實作高斯模糊。對於以下圖像:

產生的輸出影像為:

正如人們所看到的,輸出圖像包含一些未處理的邊界,這些邊界對應於當前不處理邊緣的實現決策,這讓我認為我可能在某種程度上搞砸了計算(我的意思是,這部分實現的工作原理,因此我可以在迭代圖像像素時丟棄差一錯誤)。我已經多次檢查了這段程式碼,但我找不到我的錯誤。我非常感謝有關實施的一些幫助和考慮,這可以幫助我解決問題。程式碼包含在下面。如果需要任何編輯或澄清,請告訴我!

package main

import (
    "image"
    "image/color"
    "image/draw"
    "image/jpeg"
    "math"
    "os"
)

func main() {
    f, err := os.Open("dog.jpeg")
    if err != nil {
        panic(err)
    }

    img, err := jpeg.Decode(f)
    if err != nil {
        panic(err)
    }

    newImg := gaussianBlur(img, 3)

    out, err := os.Create("dog-blurred.jpeg")
    if err != nil {
        panic(err)
    }

    err = jpeg.Encode(out, newImg, nil)
    if err != nil {
        panic(err)
    }
}

func applyGaussianFunction(x, y, stdDev float64) float64 {
    // eFactor := 1 / (2 * math.Pi * stdDev*stdDev);
    ePowNominator := -(x*x + y*y);
    ePowDenominator := 2 * stdDev*stdDev;

    return math.Pow(math.E, (ePowNominator/ePowDenominator));
}

func generateKernel(radius int) [][]float64 {
    size := 1 + (radius * 2);
    kernel := make([][]float64, size);
    stdDev := math.Max(float64(radius / 2), 1);

    sum := float64(0);

    for i := 0; i < size; i++ {
        kernel[i] = make([]float64, size);
    }

    for i := -radius; i < radius + 1; i++ {
        for j := -radius; j < radius + 1; j++ {
            val := applyGaussianFunction(float64(j), float64(i), stdDev);
            kernel[i + radius][j + radius] = val;
            sum += val;
        }
    }

    for i := 0; i < size; i++ {
        for j := 0; j < size; j++ {
            kernel[i][j] /= sum;
        }
    }

    return kernel;
}

func makeImageRGBA(src image.Image) *image.RGBA {
    b := src.Bounds().Size();
    rgba := image.NewRGBA(image.Rect(0, 0, b.X, b.Y));
    draw.Draw(rgba, rgba.Bounds(), src, image.Pt(0, 0), draw.Src);

    return rgba;
}

func gaussianBlur(img image.Image, radius int) image.Image {
    size := img.Bounds().Size();
    rgbaImg := image.NewRGBA(image.Rect(0, 0, size.X, size.Y));

    kernel := generateKernel(radius);

    for y := radius; y < size.Y - radius; y++ {
        for x := radius; x < size.X - radius; x++ {
            var nr, ng, nb, na float64 = 0, 0, 0, 0;

            for i := -radius; i < radius + 1; i++ {
                for j := -radius; j < radius + 1; j++ {
                    // NEW: Get pixels from original Image
                    pr, pg, pb, pa := img.At(x - j, y - i).RGBA();

                    nr += float64(pr) * kernel[i + radius][j + radius];
                    ng += float64(pg) * kernel[i + radius][j + radius];
                    nb += float64(pb) * kernel[i + radius][j + radius];
                    na += float64(pa) * kernel[i + radius][j + radius];
                }
            }

            // Handle overflow by using 64-bit alphapremultiplied values
            rgbaImg.Set(x, y, color.RGBA64{uint16(nr), uint16(ng), uint16(nb), uint16(na)});
        }
    }

    return rgbaImg;
}

編輯

  • 我修改了程式碼,以便從原始圖像中讀取像素,而不是從 rgbaimg
  • #我還從 applygaussianfunction 函數註解了 efactor,因為我已經使用 sum 變數規範化核心
  • 修改了 .set 方法以使用 64 位元 rgba 結構

這是新生成的圖片

那些黑色邊框很容易解決,我已經在解決它們了。這不再是問題的一部分。

解決方法

您正在從正在寫入的相同映像中讀取內容。您應該從原始圖像中讀取:

pr, pg, pb, pa := img.at(x+j, y+i).rgba()

編輯: 此外, image.at 傳回 color.rgba,而 func (color.rgba) rgba 回傳0 到 0xffff 範圍。然而 color.rgba 建構子期望它們在 0 到 255 範圍內。在寫入結果時,您可能需要使用 color.rgba64

rgbaImg.Set(x, y, color.RGBA64{uint16(nr), uint16(ng), uint16(nb), uint16(na)});

以上是高斯模糊實作會產生奇怪的輸出的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:stackoverflow.com。如有侵權,請聯絡admin@php.cn刪除