Javascript影像處理—平滑處理實作原理_javascript技巧
前言
上一篇文章,我們講解了影像的虛擬邊緣,這篇文章開始進行平滑(也就是模糊)處理。
基本原理
這裡直接引用OpenCV 2.4 C 平滑處理和OpenCV 2.4 C 邊緣梯度計算的相關內容:
平滑也稱模糊, 是一項簡單且使用頻率很高的影像處理方法。
平滑處理時需要使用到一個濾波器
。 最常用的濾波器是線性 濾波器,線性濾波處理的輸出像素值(例如:)是輸入像素值(例如:
)的加權平均值:
, 它只是一個加權係數。
稱為核
這裡涉及一種叫做「卷積」的運算,那麼卷積是什麼呢?
卷積是在每個影像區塊與某個算子(核)之間進行的運算。
核? !
nbsp;dsds
核就是一個固定大小的數值數組。此陣列有一個錨點
,一般位於陣列中央。
可是這怎麼運算啊?
假如你想得到影像的某個特定位置的捲積值,可用下列方法計算:
將核的錨點放在該特定位置的像素上,同時,核內的其他值與該像素鄰域的各像素重合;將核內各值與相應像素值相乘,並將乘積相加;將所得結果放到與錨點對應的像素上;對影像所有像素重複上述過程。
用公式表示上述過程如下:
在影像邊緣的捲積怎麼辦呢?
計算卷積前,需要透過複製來源影像的邊界來建立虛擬像素,這樣邊緣的地方也有足夠像素計算卷積了。這就是為什麼上一篇文章需要做虛擬邊緣函數。
平均值平滑
均值平滑其實就是內核元素全是1的捲積運算,然後再除以內核的大小,用數學表達式來表示就是:
下面我們來實現平均值平滑函數blur:
程式碼如下:
if(__src.type && __src.type == "CV_RGBA"){
var height = __src.row, wid. col,
dst = __dst || new Mat(height, width, CV_RGBA),
dstData = dst.data;
var size1 = __size1 || 3,
size2 = __size2 || size🎜>size2 = __size2 ||size1,
size = size1 * size2;
if(size1 % 2 !== 1 || size2 % 2 !== 1){
console.error("size大小必須是奇數"); return __src;
}
var startX = Math.floor(size1 / 2),
startY = Math.floor(size2 / 2);
var withBorderMat = copyMakeBorder(__sstart , 0, 0, __borderType),
mData = withBorderMat.data,
mWidth = withBorderMat.col;
var newValue, nowX, offsetY, offsetI;
var newValue, nowX, offsetY, offsetI;
i, j3, j , y, x;
for(i = height; i--;){
offsetI = i * width;
for(j = width; j--;){
for(c = 3; c--;){
newValue = 0;
for(y = size2; y--;){
offsetY = (y i) * mWidth * 4;
for(x = size1; x--;){
nowX = (x j) * 4 c;
newValue = mData[offsetY nowX];
}
}
dstData[(joff offsetI) * 4 c] = newValue / size;
}
dstData[(j offsetI) * 4 3] = mData[offsetY startY * mWidth * 4 (j startX) * 4 3];
};
}
}else{
console.error("不支援型別。 ");
其中size1和size2分別是核的橫向和縱向大小,且必須是正奇數。
高斯平滑
最有用的濾波器 (儘管不是最快的)。 高斯濾波是將輸入數組的每一個像素點與高斯內核
卷積將卷積和作為輸出像素值。參考一維高斯函數,我們可以看見,他是個中間大兩邊小的函數。
所以高斯濾波器其加權數是中間大,四周小的。
其二維高斯函數為:
其中




這裡參考OpenCV的實現,不過應該還有優化空間,因為還沒用到分離濾波器。
首先我們先做一個getGaussianKernel來傳回高斯濾波器的一維數組。
function getGaussianKernel(__nianKernel(__s) SMALL_GAUSSIAN_SIZE = 7,
smallGaussianTab = [[1],
[0.25, 0.5, 0.25],
[0.0625, 0.25, 0.375,
[0.0625, 0.25, 0.375, 0.25, 0. , 0.21875, 0.28125, 0.21875, 0.109375, 0.03125]
];
var fixedKernel = __n & 2 == 1 && __n
var sigmaX = __sigma > 0 ? __sigma : ((__n - 1) * 0.5 - 1) * 0.3 0.8,
scale2X = -0.5 / (sigmaX * sigmaX);
var i, x, t, kernel = [];
for(i = 0; i x = i - (__n - 1) * 0.5;
t = fixedKernel ? fixedKernel[i] : Math.exp(scale2X * x * x);
kernel[i] = t;
sum = t;
}
sum = 1 / sum;
for(i = __n; i--;){
kernel[i] *= sum;
}
return kernel;
};
然後經過兩個這個一維數組,便可以計算出一個完整的高斯內核,再利用blur裡面用到的循環方法,就可以算出高斯平滑後的矩陣了。
函數GaussianBlur(__src, __size1, __size2, __sigma1, __sigma2, __borderType, __dst){
if(__src.type && __src.type == "CV_RGBA") ==== .row,
寬度= __src.col,
dst = __dst || new Mat(高度, 寬度, CV_RGBA),
dstData = dst.data;
var sigma1 = __sigma1 || 0,
sigma2 = __sigma2 || __西格瑪1;
var size1 = __size1 || Math.round(sigma1 * 6 1) | Math.round(sigma1 * 6 1) | 1、
尺寸2 = __尺寸2 || Math.round(sigma2 * 6 1) | 數學.round(sigma2 * 6 1) | 1、
尺寸=尺寸1*尺寸2;
if(size1 % 2 !== 1 || size2 % 2 !== 1){
console.error("size必須是奇數。");
返回__src;
}
var startX = Math.floor(size1 / 2),
startY = Math.floor(size2 / 2);
var withBorderMat = copyMakeBorder(__src, startY, startX, 0, 0, __borderType),
mData = withBorderM. >mWidth = withBorderMat.col;
var kernel1 = getGaussianKernel(size1, sigma1),
kernel2,
kernel = new Array(size1 * size2); === size2 && sigma1 === sigma2)
kernel2 = kernel1;
else
kernel2 = getGaussianKernel(size2, sigma2);
for(i = kernel2.length; i--;){
for(j = kernel1.length; j--;){
kernel[i * size1 j] = kernel2 [ i] * 內核1[j];
}
}
var newValue, nowX, offsetY, offsetI;
for(i = 高度; i--;) {
offsetI = i * 寬度;
for(j = width; j--;){
for(c = 3; c--;){
newValue = 0;
for(y = size2; y--;){
offsetY = (y i) * mWidth * 4;
for(x = size1; x--;){
nowX = (x j) * 4 c;
newValue = (mData[offsetY nowX] * kernel[y * size1 x]);
}
}
dstData[(j offsetI) * 4 c] = newValue;
dstData[(j offsetI) * 4 c] = newValue;
dstData[(j offsetI) * 4 c] = newValue;
}
dstData[(j offsetI) * 4 3] = mData[offsetY startY * mWidth * 4 (j startX) * 4 3];
}
}
}else{
console.error("不支援的類型");
}
返回目的地;
}
中位數輔助將每個像素的像素以鄰域(以目前像素為中心的適配器區域)像素的
中位數
取代 。依然使用blur裡面所佔用的循環,只要得到核中的所有值,再透過排序便可以得到中位數,然後依靠該值替代。
var height = __src.row,
寬度= __src.col,
dst = __dst || new Mat(高度, 寬度, CV_RGBA),
dstData = dst.data;
var size1 = __size1 || 3、
尺寸2 = __尺寸2 ||尺寸1,
尺寸=尺寸1*尺寸2;
if(size1 % 2 !== 1 || size2 % 2 !== 1){
console.error("size必須是奇數");
回傳__src;
}
var startX = Math.floor(size1 / 2),
startY = Math.floor(size2 / 2);
var withBorderMat = copyMakeBorder(__src,orderstartY, startX, __bType ),
mData = withBorderMat.data,
mWidth = withBorderMat.col;
var newValue = [], nowX, offsetY, offsetI;
var i, j, c, y,, j, j, c, y, j x;
for(i = 高度; i--;){
offsetI = i * 寬度;
for(j = width; j--;){
for(c = 3; c--;){
for(y = size2; y--;){
offsetY = (y i) * m寬度* 4;
for(x = size1; x-- ;){
nowX = (x j) * 4 c;
newValue[y * size1 x] = mData[offsetY nowX];
}
}
newValue.sort();
dstData[(j offsetI) * 4 c] = newValue[Math.round(size / 2)];
}
dstData[(j offsetI) * 4 3] = mData[offsetY startY * mWidth * 4 (j startX) * 4 3];
}
}
}else{
console.error("型別不支援");
}
回傳目的地;
};

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

Wasserstein距離,又稱EarthMover'sDistance(EMD),是一種用於測量兩個機率分佈之間差異的測量方法。相較於傳統的KL散度或JS散度,Wasserstein距離考慮了分佈之間的結構訊息,因此在許多影像處理任務中展現出更好的性能。透過計算兩個分佈之間的最小運輸成本,Wasserstein距離能夠測量將一個分佈轉換為另一個分佈所需的最小工作量。這種度量方法能夠捕捉到分佈之間的幾何差異,從而在影像生成、風格遷移等任務中發揮重要作用。因此,Wasserstein距離成為了概

VisionTransformer(VIT)是Google提出的一種基於Transformer的圖片分類模型。不同於傳統CNN模型,VIT將圖像表示為序列,並透過預測圖像的類別標籤來學習圖像結構。為了實現這一點,VIT將輸入影像劃分為多個補丁,並將每個補丁中的像素透過通道連接,然後進行線性投影以達到所需的輸入維度。最後,每個補丁被展平為單一向量,從而形成輸入序列。透過Transformer的自註意力機制,VIT能夠捕捉到不同補丁之間的關係,並進行有效的特徵提取和分類預測。這種序列化的影像表示方法為

C#開發中如何處理影像處理和圖形介面設計問題,需要具體程式碼範例引言:在現代軟體開發中,影像處理和圖形介面設計是常見的需求。而C#作為一種通用的高階程式語言,具有強大的影像處理和圖形介面設計能力。本文將以C#為基礎,討論如何處理影像處理和圖形介面設計問題,並給出詳細的程式碼範例。一、影像處理問題:影像讀取和顯示:在C#中,影像的讀取和顯示是基本操作。可以使用.N

超解析度影像重建是利用深度學習技術,如卷積神經網路(CNN)和生成對抗網路(GAN),從低解析度影像中生成高解析度影像的過程。該方法的目標是透過將低解析度影像轉換為高解析度影像,從而提高影像的品質和細節。這種技術在許多領域都有廣泛的應用,如醫學影像、監視攝影、衛星影像等。透過超解析度影像重建,我們可以獲得更清晰、更具細節的影像,有助於更準確地分析和識別影像中的目標和特徵。重建方法超解析度影像重建的方法通常可以分為兩類:基於插值的方法和基於深度學習的方法。 1)基於插值的方法基於插值的超解析度影像重

Java開發:影像辨識與處理實務指南摘要:隨著電腦視覺和人工智慧的快速發展,影像辨識和處理在各個領域都發揮了重要作用。本文將介紹如何利用Java語言實現影像辨識和處理,並提供具體的程式碼範例。一、影像辨識的基本原理影像辨識是指利用電腦科技對影像進行分析與理解,從而辨識出影像中的物件、特徵或內容。在進行影像辨識之前,我們需要先了解一些基本的影像處理技術,如圖

舊照片修復是利用人工智慧技術對舊照片進行修復、增強和改善的方法。透過電腦視覺和機器學習演算法,該技術能夠自動識別並修復舊照片中的損壞和缺陷,使其看起來更加清晰、自然和真實。舊照片修復的技術原理主要包括以下幾個面向:1.影像去雜訊和增強修復舊照片時,需要先進行去雜訊和增強處理。可以使用影像處理演算法和濾波器,如均值濾波、高斯濾波、雙邊濾波等,來解決雜訊和色斑問題,進而提升照片的品質。 2.影像復原和修復在舊照片中,可能存在一些缺陷和損壞,例如刮痕、裂縫、褪色等。這些問題可以透過影像復原和修復演算法來解決

PHP學習筆記:人臉辨識與影像處理前言:隨著人工智慧技術的發展,人臉辨識和影像處理成為了熱門話題。在實際應用中,人臉辨識與影像處理多用於安全監控、人臉解鎖、卡牌比對等方面。而PHP作為常用的伺服器端腳本語言,也可以用來實現人臉辨識與影像處理的相關功能。本篇文章將帶你了解PHP中的人臉辨識與影像處理,並附有具體的程式碼範例。一、PHP中的人臉辨識人臉辨識是一

尺度不變特徵變換(SIFT)演算法是一種用於影像處理和電腦視覺領域的特徵提取演算法。該演算法於1999年提出,旨在提高電腦視覺系統中的物體辨識和匹配性能。 SIFT演算法具有穩健性和準確性,被廣泛應用於影像辨識、三維重建、目標偵測、視訊追蹤等領域。它透過在多個尺度空間中檢測關鍵點,並提取關鍵點周圍的局部特徵描述符來實現尺度不變性。 SIFT演算法的主要步驟包括尺度空間的建構、關鍵點偵測、關鍵點定位、方向分配和特徵描述子產生。透過這些步驟,SIFT演算法能夠提取出具有穩健性和獨特性的特徵,從而實現對影像的高效
