圖像處理之Canny邊緣檢測(二)

2021-02-20 圖像處理知識庫

package com.gloomyfish.filter.study;  

  

import java.awt.image.BufferedImage;  

import java.util.Arrays;  

  

public class CannyEdgeFilter extends AbstractBufferedImageOp {  

    private float gaussianKernelRadius = 2f;  

    private int gaussianKernelWidth = 16;  

    private float lowThreshold;  

    private float highThreshold;  

      

    private int width;  

    private int height;  

    private float[] data;  

    private float[] magnitudes;  

  

    public CannyEdgeFilter() {  

        lowThreshold = 2.5f;  

        highThreshold = 7.5f;  

        gaussianKernelRadius = 2f;  

        gaussianKernelWidth = 16;  

    }  

  

    public float getGaussianKernelRadius() {  

        return gaussianKernelRadius;  

    }  

  

    public void setGaussianKernelRadius(float gaussianKernelRadius) {  

        this.gaussianKernelRadius = gaussianKernelRadius;  

    }  

  

    public int getGaussianKernelWidth() {  

        return gaussianKernelWidth;  

    }  

  

    public void setGaussianKernelWidth(int gaussianKernelWidth) {  

        this.gaussianKernelWidth = gaussianKernelWidth;  

    }  

  

    public float getLowThreshold() {  

        return lowThreshold;  

    }  

  

    public void setLowThreshold(float lowThreshold) {  

        this.lowThreshold = lowThreshold;  

    }  

  

    public float getHighThreshold() {  

        return highThreshold;  

    }  

  

    public void setHighThreshold(float highThreshold) {  

        this.highThreshold = highThreshold;  

    }  

  

    @Override  

    public BufferedImage filter(BufferedImage src, BufferedImage dest) {  

        width = src.getWidth();  

        height = src.getHeight();  

        if (dest == null)  

            dest = createCompatibleDestImage(src, null);  

          

        int[] inPixels = new int[width * height];  

        int[] outPixels = new int[width * height];  

        getRGB(src, 0, 0, width, height, inPixels);  

        int index = 0;  

        for (int row = 0; row < height; row++) {  

            int ta = 0, tr = 0, tg = 0, tb = 0;  

            for (int col = 0; col < width; col++) {  

                index = row * width + col;  

                ta = (inPixels[index] >> 24) & 0xff;  

                tr = (inPixels[index] >> 16) & 0xff;  

                tg = (inPixels[index] >> 8) & 0xff;  

                tb = inPixels[index] & 0xff;  

                int gray = (int) (0.299 * tr + 0.587 * tg + 0.114 * tb);  

                inPixels[index] = (ta << 24) | (gray << 16) | (gray << 8)  

                        | gray;  

            }  

        }  

          

          

        float kernel[][] = new float[gaussianKernelWidth][gaussianKernelWidth];  

        for(int x=0; x<gaussianKernelWidth; x++)  

        {  

            for(int y=0; y<gaussianKernelWidth; y++)  

            {  

                kernel[x][y] = gaussian(x, y, gaussianKernelRadius);  

            }  

        }  

          

        int krr = (int)gaussianKernelRadius;  

        for (int row = 0; row < height; row++) {  

            for (int col = 0; col < width; col++) {  

                index = row * width + col;  

                double weightSum = 0.0;  

                double redSum = 0;  

                for(int subRow=-krr; subRow<=krr; subRow++)  

                {  

                    int nrow = row + subRow;  

                    if(nrow >= height || nrow < 0)  

                    {  

                        nrow = 0;  

                    }  

                    for(int subCol=-krr; subCol<=krr; subCol++)  

                    {  

                        int ncol = col + subCol;  

                        if(ncol >= width || ncol <=0)  

                        {  

                            ncol = 0;  

                        }  

                        int index2 = nrow * width + ncol;  

                        int tr1 = (inPixels[index2] >> 16) & 0xff;  

                        redSum += tr1*kernel[subRow+krr][subCol+krr];  

                        weightSum += kernel[subRow+krr][subCol+krr];  

                    }  

                }  

                int gray = (int)(redSum / weightSum);  

                outPixels[index] = gray;  

            }  

        }  

          

          

        data = new float[width * height];  

        magnitudes = new float[width * height];  

        for (int row = 0; row < height; row++) {  

            for (int col = 0; col < width; col++) {  

                index = row * width + col;  

                  

                float xg = (getPixel(outPixels, width, height, col, row+1) -   

                        getPixel(outPixels, width, height, col, row) +   

                        getPixel(outPixels, width, height, col+1, row+1) -  

                        getPixel(outPixels, width, height, col+1, row))/2.0f;  

                float yg = (getPixel(outPixels, width, height, col, row)-  

                        getPixel(outPixels, width, height, col+1, row) +  

                        getPixel(outPixels, width, height, col, row+1) -  

                        getPixel(outPixels, width, height, col+1, row+1))/2.0f;  

                  

                data[index] = hypot(xg, yg);  

                if(xg == 0)  

                {  

                    if(yg > 0)  

                    {  

                        magnitudes[index]=90;                         

                    }  

                    if(yg < 0)  

                    {  

                        magnitudes[index]=-90;  

                    }  

                }  

                else if(yg == 0)  

                {  

                    magnitudes[index]=0;  

                }  

                else  

                {  

                    magnitudes[index] = (float)((Math.atan(yg/xg) * 180)/Math.PI);                    

                }  

                  

                magnitudes[index] += 90;  

            }  

        }  

          

          

        Arrays.fill(magnitudes, 0);  

        for (int row = 0; row < height; row++) {  

            for (int col = 0; col < width; col++) {  

                index = row * width + col;  

                float angle = magnitudes[index];  

                float m0 = data[index];  

                magnitudes[index] = m0;  

                if(angle >=0 && angle < 22.5)   

                {  

                    float m1 = getPixel(data, width, height, col-1, row);  

                    float m2 = getPixel(data, width, height, col+1, row);  

                    if(m0 < m1 || m0 < m2)  

                    {  

                        magnitudes[index] = 0;  

                    }  

                }  

                else if(angle >= 22.5 && angle < 67.5)   

                {  

                    float m1 = getPixel(data, width, height, col+1, row-1);  

                    float m2 = getPixel(data, width, height, col-1, row+1);  

                    if(m0 < m1 || m0 < m2)  

                    {  

                        magnitudes[index] = 0;  

                    }  

                }  

                else if(angle >= 67.5 && angle < 112.5)   

                {  

                    float m1 = getPixel(data, width, height, col, row+1);  

                    float m2 = getPixel(data, width, height, col, row-1);  

                    if(m0 < m1 || m0 < m2)  

                    {  

                        magnitudes[index] = 0;  

                    }  

                }  

                else if(angle >=112.5 && angle < 157.5)   

                {  

                    float m1 = getPixel(data, width, height, col-1, row-1);  

                    float m2 = getPixel(data, width, height, col+1, row+1);  

                    if(m0 < m1 || m0 < m2)  

                    {  

                        magnitudes[index] = 0;  

                    }  

                }  

                else if(angle >=157.5)   

                {  

                    float m1 = getPixel(data, width, height, col, row+1);  

                    float m2 = getPixel(data, width, height, col, row-1);  

                    if(m0 < m1 || m0 < m2)  

                    {  

                        magnitudes[index] = 0;  

                    }  

                }  

            }  

        }  

          

        float min = 255;  

        float max = 0;  

        for(int i=0; i<magnitudes.length; i++)  

        {  

            if(magnitudes[i] == 0) continue;  

            min = Math.min(min, magnitudes[i]);  

            max = Math.max(max, magnitudes[i]);  

        }  

        System.out.println("Image Max Gradient = " + max + " Mix Gradient = " + min);  

  

          

          

        Arrays.fill(data, 0);  

        int offset = 0;  

        for (int row = 0; row < height; row++) {  

            for (int col = 0; col < width; col++) {  

                if(magnitudes[offset] >= highThreshold && data[offset] == 0)  

                {  

                    edgeLink(col, row, offset, lowThreshold);  

                }  

                offset++;  

            }  

        }  

          

          

        for(int i=0; i<inPixels.length; i++)  

        {  

            int gray = clamp((int)data[i]);  

            outPixels[i] = gray > 0 ? -1 : 0xff000000;       

        }  

        setRGB(dest, 0, 0, width, height, outPixels );  

        return dest;  

    }  

      

    public int clamp(int value) {  

        return value > 255 ? 255 :  

            (value < 0 ? 0 : value);  

    }  

      

    private void edgeLink(int x1, int y1, int index, float threshold) {  

        int x0 = (x1 == 0) ? x1 : x1 - 1;  

        int x2 = (x1 == width - 1) ? x1 : x1 + 1;  

        int y0 = y1 == 0 ? y1 : y1 - 1;  

        int y2 = y1 == height -1 ? y1 : y1 + 1;  

          

        data[index] = magnitudes[index];  

        for (int x = x0; x <= x2; x++) {  

            for (int y = y0; y <= y2; y++) {  

                int i2 = x + y * width;  

                if ((y != y1 || x != x1)  

                    && data[i2] == 0   

                    && magnitudes[i2] >= threshold) {  

                    edgeLink(x, y, i2, threshold);  

                    return;  

                }  

            }  

        }  

    }  

      

    private float getPixel(float[] input, int width, int height, int col,  

            int row) {  

        if(col < 0 || col >= width)  

            col = 0;  

        if(row < 0 || row >= height)  

            row = 0;  

        int index = row * width + col;  

        return input[index];  

    }  

      

    private float hypot(float x, float y) {  

        return (float) Math.hypot(x, y);  

    }  

      

    private int getPixel(int[] inPixels, int width, int height, int col,  

            int row) {  

        if(col < 0 || col >= width)  

            col = 0;  

        if(row < 0 || row >= height)  

            row = 0;  

        int index = row * width + col;  

        return inPixels[index];  

    }  

      

    private float gaussian(float x, float y, float sigma) {  

        float xDistance = x*x;  

        float yDistance = y*y;  

        float sigma22 = 2*sigma*sigma;  

        float sigma22PI = (float)Math.PI * sigma22;  

        return (float)Math.exp(-(xDistance + yDistance)/sigma22)/sigma22PI;  

    }  

  

}  

相關焦點

  • 圖像處理之Canny邊緣檢測(一)
    一:歷史Canny邊緣檢測算法是1986年有John F. Canny開發出來一種基於圖像梯度計算的邊緣檢測算法,同時Canny本人對計算圖像邊緣提取學科的發展也是做出了很多的貢獻。儘管至今已經許多年過去,但是該算法仍然是圖像邊緣檢測方法經典算法之一。
  • Python 圖像處理 OpenCV (11):Canny 算子邊緣檢測技術
    邊緣檢測 邊緣檢測是基於灰度突變來分割圖像的常用方法,其實質是提取圖像中不連續部分的特徵。目前常見邊緣檢測算子有差分算子、 Roberts 算子、 Sobel 算子、 Prewitt 算子、 Log 算子以及 Canny 算子等。
  • 分享 | 數字圖像處理:邊緣檢測(Edge detection)
    好了話不多說,來和筆者一起看一下今天的主題-邊緣檢測。首先我們先來簡單了解一下什麼是數字圖像處理(Digital Image Processing),先看一下數字圖像主要的兩個應用領域:2.為存儲、傳輸和表示而對圖像數據進行處理,以便於機器自動理解。
  • OpenCV實戰系列(四):Canny邊緣檢測
    ,其不容易受噪聲的幹擾,它的雙閾值法可以分別檢測到強邊緣和弱邊緣,並且僅當弱邊緣與強邊緣相連時,才將弱邊緣包含在輸出結果中,這就保障了檢測到真正的弱邊緣。Canny算法不僅效果好,其使用也非常簡便,僅需一行代碼即可實現邊緣檢測,一般其工作原理如下:5)分析所有的邊緣及其之間的連接,以保留真正的邊緣並消除不明顯的邊緣;Canny(image, threshold1, threshold2, edges=None, apertureSize=None, L2gradient
  • Canny邊緣檢測原理
    邊緣檢測解析:邊緣是對象和背景之間的邊界,還能表示重疊對象之間的邊界。邊緣檢測是圖像分割的一部分,圖像分割的目的是識別出圖像中的區域。邊緣檢測是定位邊緣像素的過程,而邊緣增強是增加邊緣和背景之間的對比度以便能夠更清楚地看清邊緣的過程。邊緣跟蹤是沿著邊緣進行跟蹤的過程,這個過程通常會把邊緣像素採集到一個列表中,鏈碼算法是邊緣跟蹤算法的一個特例。
  • OpenCV(四)邊緣檢測
    點擊「藍字」關注我們上一章節,我們在使用圖像輪廓發現的時候使用了圖像邊緣檢測,一次來提高圖像輪廓發現的準確率。事實上在計算機的各個領域都有圖像邊緣檢測的身影。邊緣檢測一大優點就在於可以大幅度減少數據量,並且提出可以認為不相關的信息,保留了圖像的結構屬性。
  • 使用 Pytorch 從頭實現 Canny 邊緣檢測
    Canny濾波器當然是最著名和最常用的邊緣檢測濾波器。我會逐步解釋用於輪廓檢測的canny濾波器。Sobel 濾波為了檢測邊緣,必須對圖像應用一個濾波器來提取梯度。邊緣現在使用我們的梯度的大小被完美地檢測,但是很厚。如果我們能只保留輪廓的細線就好了。因此,我們同時計算我們的梯度的方向,這將用於保持這些細線。
  • OpenCV圖像處理常用手段
    濾波操作,模糊處理模糊處理在邊沿檢測和去噪聲方面有較為廣泛的應用。canny邊緣檢測將原始圖像轉化為灰度圖,用blur函數進行圖像模糊以降噪,然後用canny函數進行邊緣檢測。最後簡單總結一下圖像處理中概念離散傅立葉變換圖像高頻部分代表了圖像的細節、紋理信息;低頻代表了圖像的輪廓信息。低通-》模糊高通-》銳化腐蝕和膨脹是針對白色部分(高亮部分)而言的。膨脹就是對圖像高亮部分進行「領域擴張」,效果圖擁有比原圖更大的高亮區域;腐蝕是原圖中的高亮區域被蠶食,效果圖擁有比原圖更小的高亮區域。
  • 分享計算機視覺之圖像處理Python之opencv
    圖像的分割是為了目標的定位,目前定位的方法很多,但總的來說可以分為以下4類:(1)基於顏色的分割方法,這種方法主要利用顏色空間的信息,實現車牌分割,包括彩色邊緣算法、顏色距離和相似度算法等;(2)基於紋理的分割方法,這種方法主要利用車牌區域水平方向的紋理特徵進行分割,包括小波紋理、水平梯度差分紋理等;(3)基於邊緣檢測的分割方法;
  • 基於matlab邊緣提取的幾種方法的比較
    在邊緣點集合中剔除某些邊界點或填補邊界間斷點,並將這些邊緣連接成完整的線常用的檢測算子有微分算子、拉普拉斯高斯算子和canny算子。在Matlab圖像處理工具箱中,提供了edge函數利用以上算子來檢測灰度圖像的邊緣。
  • 關於利用傳統圖像處理方法進行瑕疵檢測的總結
    傳統算法方向的選擇最近做圖像處理與識別相關的事情,先從OpenCV/Matlab入手,看傳統算法在瑕疵檢測方向能做到什麼程度。瑕疵檢測關注的兩個問題瑕疵的標註對瑕疵的標註是為了更直觀的展示,主要是給人看的瑕疵的量化真正機器關心的是怎麼量化,是用數量表示還是百分比是個值得考慮的問題歷程1.圖像去噪->灰度化->二值化二值化之後就可以看到絕大部分的瑕疵點已經凸顯出來了,但是有三個問題:1. 黑點瑕疵與白點瑕疵是二值化的兩個極端,故無法同時出現。2.
  • 50 行代碼,看 Python + OpenCV 玩轉實時圖像處理!
    本文來自博客專欄《Python》本專欄專注於Python項目實戰開發應用初學OpenCV圖像處理的小夥伴肯定對什麼高斯函數、濾波處理、閾值二值化等特性非常頭疼,這裡給各位分享一個小項目,可通過攝像頭實時動態查看各類圖像處理的特點,也可對各位調參、測試有一定幫助,項目演示效果如下:
  • 邊緣和輪廓檢測——計算機視覺的應用
    其標題是「使用計算機視覺進行邊緣和輪廓檢測」。對於此項目,你還將看到描述、原始碼和圖像分類。邊緣檢測邊緣檢測是一種用於定位圖像中對象邊界的圖像處理技術。最流行和廣泛使用的算法之一是 Canny 邊緣檢測器。Canny 邊緣檢測器是一種立足點檢測算子,它使用多階段算法來檢測圖像中的各種邊緣。在 Sobel 濾波器的幫助下,找出邊緣的強度和方向。
  • 數字圖像處理中常用圖像分割算法有哪些?
    1.多數的圖像分割算法2.圖像邊緣分割3.圖像閾值分割4.基於區域的分割5.形態學分水嶺算法多數的圖像分割算法 均是基於灰度值的不連續和相似的性質。在前者中,算法以灰度突變為基礎分割一幅圖像,如圖像邊緣分割。假設圖像不同區域的邊界彼此完全不同,且與背景不同,從而允許基於灰度的局部不連續性來進行邊界檢測。
  • 在OpenCV中基於深度學習的邊緣檢測
    在這篇文章中,我們將學習如何在OpenCV中使用基於深度學習的邊緣檢測,它比目前流行的canny邊緣檢測器更精確。邊緣檢測在許多用例中是有用的,如視覺顯著性檢測,目標檢測,跟蹤和運動分析,結構從運動,3D重建,自動駕駛,圖像到文本分析等等。什麼是邊緣檢測?
  • 圖像特徵提取(顏色,紋理,形狀)
    Han, Shuicheng Yan,"An HOG-LBP Human Detector with Partial Occlusion Handling", ICCV 20093.邊緣特徵提取   邊緣檢測是圖形圖像處理、計算機視覺和機器視覺中的一個基本工具,通常用於特徵提取和特徵檢測,旨在檢測一張數字圖像中有明顯變化的邊緣或者不連續的區域,在一維空間中,類似的操作被稱作步長檢測
  • 圖像處理之目標檢測的入門總結
    利用圖像中的紋理、邊緣、顏色等信息,可以保證在選取較少窗口(幾千甚至幾百)的情況下保持較高的召回率(Recall)。有了候選區域,剩下的工作實際就是對候選區域進行圖像分類的工作(特徵提取+分類)。與R-CNN框架圖對比,可以發現主要有兩處不同:一是最後一個卷積層後加了一個ROI pooling layer,二是損失函數使用了多任務損失函數(multi-task loss),將邊框回歸 Bounding Box Regression 直接加入到CNN網絡中訓練。
  • 無人駕駛的圖像識別之車道線檢測(二)
    前言在《圖像識別之初級車道線檢測(1)》,我對計算機視覺技術的一些基本理論和OpenCV庫的使用進行了分享。這些技術包括圖像的灰度處理、邊緣提取算法、霍夫變換直線檢測算法以及數據的後處理方法。應用這些技術後,可以將圖像中近似直線的車道線檢測出來。檢測的效果如下圖紅線所示。
  • scikit-image圖像處理入門
    關注 極市平臺 公眾號 ,回復 加群,立刻申請入群~skimage是純蟒語言實現的BSD許可開源圖像處理算法庫,主要的優勢在於:scikit圖像主要模塊如下:官方主頁https://scikit-image.org/
  • Matlab 圖像處理相關函數命令
    ,method)mean2 計算矩陣元素的平均值語法:B=mean2(A)pixval  顯示圖像像素信息語法:pixval onstd2 計算矩陣元素的標準偏移語法:b=std2(A) 四、圖像分析函數:edge 圖像邊緣檢測