亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

Javascript圖像處理——邊緣梯度計算

系統 2090 0

前言

上一篇文章 ,我們講解了圖像處理中的膨脹和腐蝕函數,這篇文章將做邊緣梯度計算函數。直接摘自 OpenCV 2.4+ C++ 邊緣梯度計算

?

圖像的邊緣

圖像的邊緣從數學上是如何表示的呢?

圖像的邊緣上,鄰近的像素值應當顯著地改變了。而在數學上,導數是表示改變快慢的一種方法。 梯度值的大變預示著圖像中內容的顯著變化了。

用更加形象的圖像來解釋,假設我們有一張一維圖形。下圖中灰度值的“躍升”表示邊緣的存在:

使用一階微分求導我們可以更加清晰的看到邊緣“躍升”的存在(這里顯示為高峰值):

由此我們可以得出:邊緣可以 通過定位梯度值大于鄰域的相素的方法找到。

?

近似梯度

比如內核為3時。

首先對x方向計算近似導數:

然后對y方向計算近似導數:

然后計算梯度:

當然你也可以寫成:

?

函數實現

      
        var
      
       Sobel = 
      
        function
      
      
        (__src, __xorder, __yorder, __size, __borderType, __dst){
    (__src 
      
      && (__xorder ^ __yorder)) || error(arguments.callee, IS_UNDEFINED_OR_NULL
      
        /*
      
      
         {line} 
      
      
        */
      
      
        );
    
      
      
        if
      
      (__src.type && __src.type === "CV_GRAY"
      
        ){
        
      
      
        var
      
      
         kernel1,
            kernel2,
            height 
      
      =
      
         __src.row,
            width 
      
      =
      
         __src.col,
            dst 
      
      = __dst || 
      
        new
      
       Mat(height, width, CV_16I, 1
      
        ),
            dstData 
      
      =
      
         dst.data
            size 
      
      = __size || 3
      
        ;
        
      
      
        switch
      
      
        (size){
            
      
      
        case
      
       1
      
        :
                size 
      
      = 3
      
        ;
            
      
      
        case
      
       3
      
        :
                
      
      
        if
      
      
        (__xorder){
                    kernel 
      
      = [-1, 0, 1
      
        ,
                              
      
      -2, 0, 2
      
        ,
                              
      
      -1, 0, 1
      
        
                             ];
                }
      
      
        else
      
      
        if
      
      
        (__yorder){
                    kernel 
      
      = [-1, -2, -1
      
        ,
                               
      
      0,  0,  0
      
        ,
                               
      
      1,  2,  1
      
        
                             ];
                }
                
      
      
        break
      
      
        ;
            
      
      
        case
      
       5
      
        :
                
      
      
        if
      
      
        (__xorder){
                    kernel 
      
      = [-1, -2, 0, 2, 1
      
        ,
                              
      
      -4, -8, 0, 8, 4
      
        ,
                              
      
      -6,-12, 0,12, 6
      
        ,
                              
      
      -4, -8, 0, 8, 4
      
        ,
                              
      
      -1, -2, 0, 2, 1
      
        
                             ];
                }
      
      
        else
      
      
        if
      
      
        (__yorder){
                    kernel 
      
      = [-1, -4, -6, -4, -1
      
        ,
                              
      
      -2, -8,-12, -8, -2
      
        ,
                               
      
      0,  0,  0,  0,  0
      
        ,
                               
      
      2,  8, 12,  8,  2
      
        ,
                               
      
      1,  4,  6,  4,  1
      
        
                             ];
                }
                
      
      
        break
      
      
        ;
            
      
      
        default
      
      
        :
                error(arguments.callee, UNSPPORT_SIZE
      
      
        /*
      
      
         {line} 
      
      
        */
      
      
        );
            
        }
        
        GRAY216IC1Filter(__src, size, height, width, kernel, dstData, __borderType);

    }
      
      
        else
      
      
        {
        error(arguments.callee, UNSPPORT_DATA_TYPE
      
      
        /*
      
      
         {line} 
      
      
        */
      
      
        );
    }
    
      
      
        return
      
      
         dst;
};
      
    

這里只提供了內核大小為3和5的Sobel算子,主要原因是7或以上的內核計算就比較慢了。

輸出一個單通道的16位有符號整數矩陣。

      
        function
      
      
         GRAY216IC1Filter(__src, size, height, width, kernel, dstData, __borderType){
    
      
      
        var
      
       start = size >> 1
      
        ;
        
    
      
      
        var
      
       withBorderMat = copyMakeBorder(__src, start, start, 0, 0
      
        , __borderType);
            
    
      
      
        var
      
       mData =
      
         withBorderMat.data,
        mWidth 
      
      =
      
         withBorderMat.col;
        
    
      
      
        var
      
      
         i, j, y, x, c;
    
      
      
        var
      
      
         newValue, nowX, offsetY, offsetI;
        
    
      
      
        for
      
      (i = height; i--
      
        ;){
        offsetI 
      
      = i *
      
         width;
        
      
      
        for
      
      (j = width; j--
      
        ;){
            newValue 
      
      = 0
      
        ;
            
      
      
        for
      
      (y = size; y--
      
        ;){
                offsetY 
      
      = (y + i) *
      
         mWidth;
                
      
      
        for
      
      (x = size; x--
      
        ;){
                    nowX 
      
      = x +
      
         j;
                    newValue 
      
      += (mData[offsetY + nowX] * kernel[y * size +
      
         x]);
                }
            }
            dstData[j 
      
      + offsetI] =
      
         newValue;
        }
    }
}
      
    

然后把內核和矩陣交給這個濾波器處理,就OK了。

把這個濾波器獨立出來的原因是,可以給其他類似的計算邊緣函數使用,比如Laplacian和Scharr算子。

?

轉為無符號8位整數

由于Sobel算子算出來的是16位有符號整數,無法顯示成圖片,所以我們需要一個函數來將其轉為無符號8位整數矩陣。

convertScaleAbs函數是將每個元素取絕對值,然后放到Int8Array數組里面,由于在賦值時候大于255的數會自動轉成255,而小于0的數會自動轉成0,所以不需要我們做一個函數來負責這一工作。

      
        function
      
      
         convertScaleAbs(__src, __dst){
    __src 
      
      || error(arguments.callee, IS_UNDEFINED_OR_NULL
      
        /*
      
      
         {line} 
      
      
        */
      
      
        );
    
      
      
        var
      
       height =
      
         __src.row,
        width 
      
      =
      
         __src.col,
        channel 
      
      =
      
         __src.channel,
        sData 
      
      =
      
         __src.data;
        
    
      
      
        if
      
      (!
      
        __dst){
        
      
      
        if
      
      (channel === 1
      
        )
            dst 
      
      = 
      
        new
      
      
         Mat(height, width, CV_GRAY);
        
      
      
        else
      
      
        if
      
      (channel === 4
      
        )
            dst 
      
      = 
      
        new
      
      
         Mat(height, width, CV_RGBA);
        
      
      
        else
      
      
        
            dst 
      
      = 
      
        new
      
      
         Mat(height, width, CV_8I, channel);
    }
      
      
        else
      
      
        {
        dst 
      
      =
      
         __dst;
    }
    
    
      
      
        var
      
       dData =
      
         dst.data;

    
      
      
        var
      
      
         i, j, c;
    
    
      
      
        for
      
      (i = height; i--
      
        ;){
        
      
      
        for
      
      (j = width * channel; j--
      
        ;){
            dData[i 
      
      * width * channel + j] = Math.abs(sData[i * width * channel +
      
         j]);
        }
    }
    
    
      
      
        return
      
      
         dst;
}
      
    

?

按比例合并值

我們還需要一個函數將x方向梯度計算值和y方向梯度計算值疊加起來。

      
        var
      
       addWeighted = 
      
        function
      
      
        (__src1, __alpha, __src2, __beta, __gamma, __dst){
    (__src1 
      
      && __src2) || error(arguments.callee, IS_UNDEFINED_OR_NULL
      
        /*
      
      
         {line} 
      
      
        */
      
      
        );
    
      
      
        var
      
       height =
      
         __src1.row,
        width 
      
      =
      
         __src1.col,
        alpha 
      
      = __alpha || 0
      
        ,
        beta 
      
      = __beta || 0
      
        ,
        channel 
      
      =
      
         __src1.channel,
        gamma 
      
      = __gamma || 0
      
        ;
    
      
      
        if
      
      (height !== __src2.row || width !== __src2.col || channel !==
      
         __src2.channel){
        error(arguments.callee, 
      
      "Src2 must be the same size and channel number as src1!"
      
        /*
      
      
         {line} 
      
      
        */
      
      
        );
        
      
      
        return
      
      
        null
      
      
        ;
    }
    
    
      
      
        if
      
      (!
      
        __dst){
        
      
      
        if
      
      (__src1.type.match(/CV\_\d+/
      
        ))
            dst 
      
      = 
      
        new
      
      
         Mat(height, width, __src1.depth(), channel);
        
      
      
        else
      
      
        
            dst 
      
      = 
      
        new
      
      
         Mat(height, width, __src1.depth());
    }
      
      
        else
      
      
        {
        dst 
      
      =
      
         __dst;
    }
    
    
      
      
        var
      
       dData =
      
         dst.data,
        s1Data 
      
      =
      
         __src1.data,
        s2Data 
      
      =
      
         __src2.data;
    
    
      
      
        var
      
      
         i;
    
    
      
      
        for
      
      (i = height * width * channel; i--
      
        ;)
        dData[i] 
      
      = __alpha * s1Data[i] + __beta * s2Data[i] +
      
         gamma;
        
    
      
      
        return
      
      
         dst;
};
      
    

這個函數很簡單,實際上只是對兩個矩陣的對應元素按固定比例相加而已。

?

效果圖

Javascript圖像處理——邊緣梯度計算_第1張圖片

?

系列目錄

Javascript圖像處理系列

Javascript圖像處理——邊緣梯度計算


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 四虎影院中文字幕 | 久久久久国产精品免费网站 | 天天做天天做天天综合网 | 综合色在线观看 | 网站免费黄色 | 狠狠色噜噜狠狠狠狠98 | 欧美性狂猛bbbbbbxxxx | 国产成人综合亚洲一区 | 欧美黄页网| 亚洲一级视频在线观看 | 噜噜噜天天躁狠狠躁夜夜精品 | 久久精品123 | 涩涩视频免费观看 | 在线视频欧美日韩 | 国产一区二区精品在线观看 | 四虎a级欧美在线观看 | 色综合一区 | 国产精品久久久久久久久久免费 | 欧美 日本 国产 | 日日碰碰 | 免费一级成人免费观看 | 久久99久久精品97久久综合 | 精品无人区乱码一区二区三区手机 | 福利在线视频观看 | 国产香蕉视频在线观看 | 国产九九在线观看播放 | 最近免费中文字幕大全免费版视频 | 欧美一级特黄一片免费 | 国产国产成人人免费影院 | 日韩欧美亚洲每的更新在线 | 五月天婷五月天综合网在线 | 日韩新片王| 91国自产精品中文字幕亚洲 | 国产伊人久久 | 亚洲精品中文字幕乱码三区一二 | 国产精品色婷婷在线观看 | 国产一级做a爱免费视频 | 国产三级久久久精品麻豆三级 | 97在线碰碰观看免费高清 | 老司机深夜免费福利 | 国产香蕉网 |