Javascript圖像處理思路及實(shí)現(xiàn)代碼
更新時(shí)間:2012年12月25日 14:08:14 作者:
HTML5的canvas提供了getImageData接口來獲取canvas中的數(shù)據(jù),所以我們能夠先用drawImage接口將圖片畫在canvas上然后再通過getImageData得到圖片數(shù)據(jù)矩陣,需要了解的朋友可以詳細(xì)參考下
思路
HTML5的canvas提供了getImageData接口來獲取canvas中的數(shù)據(jù),所以我們能夠先用drawImage接口將圖片畫在canvas上然后再通過getImageData得到圖片數(shù)據(jù)矩陣。
需要注意,雖然IE9開始支持了canvas接口,但是其getImageData獲取的數(shù)據(jù)并不是以標(biāo)準(zhǔn)的TypedArray方式存儲(chǔ)的,或者說IE9沒有提供對(duì)WebGL Native binary data的支持,所以如果需要對(duì)IE9支持,下面的矩陣需要用Array的方式保存。雖然IE9以下版本(例如IE8)有開源項(xiàng)目explorercanvas提供canvas支持,但很可惜G_vmlCanvasManager并沒有提供位圖數(shù)據(jù)獲取接口。TypedArray的相關(guān)內(nèi)容可以參考HTML5的新數(shù)組
基本矩陣
在圖像處理中,矩陣計(jì)算是非常重要的內(nèi)容,所以我們首先來建立一個(gè)矩陣模型。
通過getImageData接口獲取的ImageData雖然具有類似矩陣的結(jié)構(gòu),但是他的結(jié)構(gòu)是不可變的,不適合擴(kuò)展,所以我們選擇在Javascript中自建一個(gè)矩陣。
function Mat(__row, __col, __data, __buffer){
this.row = __row || 0;
this.col = __col || 0;
this.channel = 4;
this.buffer = __buffer || new ArrayBuffer(__row * __col * 4);
this.data = new Uint8ClampedArray(this.buffer);
__data && this.data.set(__data);
this.bytes = 1;
this.type = "CV_RGBA";
}
row - 代表矩陣的行數(shù)
col - 代表矩陣的列數(shù)
channel - 代表通道數(shù)量,因?yàn)橥ㄟ^getImageData獲取的圖片數(shù)據(jù)是以RGBA色彩空間進(jìn)行描述的,即有Red(紅)、Green(綠)、Blue(藍(lán))和Alpha(不透明度)四個(gè)通道。
buffer - 數(shù)據(jù)所用的ArrayBuffer引用。
data - 圖片的Uint8ClampedArray數(shù)組數(shù)據(jù)。
bytes - 每個(gè)數(shù)據(jù)單位占用字節(jié),因?yàn)槭莡int8數(shù)據(jù)類型,所以占用字節(jié)數(shù)為1。
type - 數(shù)據(jù)類型是CV_RGBA。
圖片數(shù)據(jù)轉(zhuǎn)成矩陣的方法
function imread(__image){
var width = __image.width,
height = __image.height;
iResize(width, height);
iCtx.drawImage(__image, 0, 0);
var imageData = iCtx.getImageData(0, 0, width, height),
tempMat = new Mat(height, width, imageData.data);
imageData = null;
iCtx.clearRect(0, 0, width, height);
return tempMat;
}
注意:這里的__image指的是Image對(duì)象,不是字符串URL。因?yàn)闉g覽器中Image的讀取是一個(gè)異步過程,并不能立刻返回相應(yīng)的Mat對(duì)象,所以這個(gè)函數(shù)應(yīng)當(dāng)這樣使用:
var img = new Image();
img.onload = function(){
var myMat = cv.imread(img);
};
img.src = "1.jpg";
iCtx和iResize方法是一個(gè)全局變量,允許給其它函數(shù)公用:
var iCanvas = document.createElement("canvas"),
iCtx = iCanvas.getContext("2d");
function iResize(__width, __height){
iCanvas.width = __width;
iCanvas.height = __height;
}
我們來看一下drawImage方法:
用途
在canvas上繪制一個(gè)圖片。
語法
context.drawImage(img,x,y);
context.drawImage(img,x,y,width,height);
context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height);
例子
還有g(shù)etImageData方法:
用途
獲取canvas中的圖像數(shù)據(jù)。
數(shù)據(jù)是以RGBA色彩空間返回的,即:
R - 紅色通道大小
G - 綠色通道大小
B - 藍(lán)色通道大小
A - 不透明程度大小
語法
context.getImageData(x,y,width,height);
例子
red = imgData.data[0];
green = imgData.data[1];
blue = imgData.data[2];
alpha = imgData.data[3];
矩陣轉(zhuǎn)成圖像數(shù)據(jù)的方法
經(jīng)過處理后的矩陣,需要一個(gè)方法變成ImageData,然后我們就可以通過putImageData方法,在canvas上繪制經(jīng)過處理的圖像了。
function RGBA2ImageData(__imgMat){
var width = __imgMat.col,
height = __imgMat.row,
imageData = iCtx.createImageData(width, height);
imageData.data.set(__imgMat.data);
return imageData;
}
我們來看一下putImageData方法:
用途
通過圖像數(shù)據(jù),在canvas上繪制圖像。
語法
context.putImageData(imgData,x,y,dirtyX,dirtyY,dirtyWidth,dirtyHeight);
將彩色圖轉(zhuǎn)換成灰度圖
最后我們進(jìn)行一個(gè)簡單的色彩空間變換,將圖像從RGBA轉(zhuǎn)成GRAY。
function cvtColor(__src){
if(__src.type && __src.type === "CV_RGBA"){
var row = __src.row,
col = __src.col;
var dst = new Mat(row, col);
data = dst.data,
data2 = __src.data;
var pix1, pix2, pix = __src.row * __src.col * 4;
while (pix){
data[pix -= 4] = data[pix1 = pix + 1] = data[pix2 = pix + 2] = (data2[pix] * 299 + data2[pix1] * 587 + data2[pix2] * 114) / 1000;
data[pix + 3] = data2[pix + 3];
}
}else{
return src;
}
return dst;
}
參考OpenCV文檔中的轉(zhuǎn)換公式:
RGBA to Gray: Y <- 0.299 * R + 0.587 * G + 0.114 * B
Gray to RGBA: R <- Y, G <- Y, B <- Y, A <- 255
我們可以得出RGBA to GRAY(指的是擁有4個(gè)通道)對(duì)應(yīng)映射關(guān)系應(yīng)該為:
RGBA to RGBA(GRAY): R1 = G1 = B1 <- 0.299 * R + 0.587 * G + 0.114 * B , A1 <- A
HTML5的canvas提供了getImageData接口來獲取canvas中的數(shù)據(jù),所以我們能夠先用drawImage接口將圖片畫在canvas上然后再通過getImageData得到圖片數(shù)據(jù)矩陣。
需要注意,雖然IE9開始支持了canvas接口,但是其getImageData獲取的數(shù)據(jù)并不是以標(biāo)準(zhǔn)的TypedArray方式存儲(chǔ)的,或者說IE9沒有提供對(duì)WebGL Native binary data的支持,所以如果需要對(duì)IE9支持,下面的矩陣需要用Array的方式保存。雖然IE9以下版本(例如IE8)有開源項(xiàng)目explorercanvas提供canvas支持,但很可惜G_vmlCanvasManager并沒有提供位圖數(shù)據(jù)獲取接口。TypedArray的相關(guān)內(nèi)容可以參考HTML5的新數(shù)組
基本矩陣
在圖像處理中,矩陣計(jì)算是非常重要的內(nèi)容,所以我們首先來建立一個(gè)矩陣模型。
通過getImageData接口獲取的ImageData雖然具有類似矩陣的結(jié)構(gòu),但是他的結(jié)構(gòu)是不可變的,不適合擴(kuò)展,所以我們選擇在Javascript中自建一個(gè)矩陣。
復(fù)制代碼 代碼如下:
function Mat(__row, __col, __data, __buffer){
this.row = __row || 0;
this.col = __col || 0;
this.channel = 4;
this.buffer = __buffer || new ArrayBuffer(__row * __col * 4);
this.data = new Uint8ClampedArray(this.buffer);
__data && this.data.set(__data);
this.bytes = 1;
this.type = "CV_RGBA";
}
row - 代表矩陣的行數(shù)
col - 代表矩陣的列數(shù)
channel - 代表通道數(shù)量,因?yàn)橥ㄟ^getImageData獲取的圖片數(shù)據(jù)是以RGBA色彩空間進(jìn)行描述的,即有Red(紅)、Green(綠)、Blue(藍(lán))和Alpha(不透明度)四個(gè)通道。
buffer - 數(shù)據(jù)所用的ArrayBuffer引用。
data - 圖片的Uint8ClampedArray數(shù)組數(shù)據(jù)。
bytes - 每個(gè)數(shù)據(jù)單位占用字節(jié),因?yàn)槭莡int8數(shù)據(jù)類型,所以占用字節(jié)數(shù)為1。
type - 數(shù)據(jù)類型是CV_RGBA。
圖片數(shù)據(jù)轉(zhuǎn)成矩陣的方法
復(fù)制代碼 代碼如下:
function imread(__image){
var width = __image.width,
height = __image.height;
iResize(width, height);
iCtx.drawImage(__image, 0, 0);
var imageData = iCtx.getImageData(0, 0, width, height),
tempMat = new Mat(height, width, imageData.data);
imageData = null;
iCtx.clearRect(0, 0, width, height);
return tempMat;
}
注意:這里的__image指的是Image對(duì)象,不是字符串URL。因?yàn)闉g覽器中Image的讀取是一個(gè)異步過程,并不能立刻返回相應(yīng)的Mat對(duì)象,所以這個(gè)函數(shù)應(yīng)當(dāng)這樣使用:
復(fù)制代碼 代碼如下:
var img = new Image();
img.onload = function(){
var myMat = cv.imread(img);
};
img.src = "1.jpg";
iCtx和iResize方法是一個(gè)全局變量,允許給其它函數(shù)公用:
復(fù)制代碼 代碼如下:
var iCanvas = document.createElement("canvas"),
iCtx = iCanvas.getContext("2d");
function iResize(__width, __height){
iCanvas.width = __width;
iCanvas.height = __height;
}
我們來看一下drawImage方法:
用途
在canvas上繪制一個(gè)圖片。
語法
context.drawImage(img,x,y);
context.drawImage(img,x,y,width,height);
context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height);
例子
還有g(shù)etImageData方法:
用途
獲取canvas中的圖像數(shù)據(jù)。
數(shù)據(jù)是以RGBA色彩空間返回的,即:
R - 紅色通道大小
G - 綠色通道大小
B - 藍(lán)色通道大小
A - 不透明程度大小
語法
context.getImageData(x,y,width,height);
例子
復(fù)制代碼 代碼如下:
red = imgData.data[0];
green = imgData.data[1];
blue = imgData.data[2];
alpha = imgData.data[3];
矩陣轉(zhuǎn)成圖像數(shù)據(jù)的方法
經(jīng)過處理后的矩陣,需要一個(gè)方法變成ImageData,然后我們就可以通過putImageData方法,在canvas上繪制經(jīng)過處理的圖像了。
復(fù)制代碼 代碼如下:
function RGBA2ImageData(__imgMat){
var width = __imgMat.col,
height = __imgMat.row,
imageData = iCtx.createImageData(width, height);
imageData.data.set(__imgMat.data);
return imageData;
}
我們來看一下putImageData方法:
用途
通過圖像數(shù)據(jù),在canvas上繪制圖像。
語法
context.putImageData(imgData,x,y,dirtyX,dirtyY,dirtyWidth,dirtyHeight);
將彩色圖轉(zhuǎn)換成灰度圖
最后我們進(jìn)行一個(gè)簡單的色彩空間變換,將圖像從RGBA轉(zhuǎn)成GRAY。
復(fù)制代碼 代碼如下:
function cvtColor(__src){
if(__src.type && __src.type === "CV_RGBA"){
var row = __src.row,
col = __src.col;
var dst = new Mat(row, col);
data = dst.data,
data2 = __src.data;
var pix1, pix2, pix = __src.row * __src.col * 4;
while (pix){
data[pix -= 4] = data[pix1 = pix + 1] = data[pix2 = pix + 2] = (data2[pix] * 299 + data2[pix1] * 587 + data2[pix2] * 114) / 1000;
data[pix + 3] = data2[pix + 3];
}
}else{
return src;
}
return dst;
}
參考OpenCV文檔中的轉(zhuǎn)換公式:
RGBA to Gray: Y <- 0.299 * R + 0.587 * G + 0.114 * B
Gray to RGBA: R <- Y, G <- Y, B <- Y, A <- 255
我們可以得出RGBA to GRAY(指的是擁有4個(gè)通道)對(duì)應(yīng)映射關(guān)系應(yīng)該為:
RGBA to RGBA(GRAY): R1 = G1 = B1 <- 0.299 * R + 0.587 * G + 0.114 * B , A1 <- A
相關(guān)文章
Java中int與integer的區(qū)別(基本數(shù)據(jù)類型與引用數(shù)據(jù)類型)
這篇文章主要介紹了int與integer的區(qū)別(基本數(shù)據(jù)類型與引用數(shù)據(jù)類型),簡單的說 int 是基本數(shù)據(jù)類型,integer 是引用數(shù)據(jù)類型,具體區(qū)別詳解大家參考下本文2017-02-02
JavaScript數(shù)組操作學(xué)習(xí)之splice()函數(shù)入門與精通
這篇文章介紹了JavaScript數(shù)組操作中的splice()方法,詳細(xì)講解了其定義、語法和用法,并通過實(shí)例展示了如何使用該方法進(jìn)行數(shù)組元素的添加、刪除和替換,需要的朋友可以參考下2024-11-11
詳解JavaScript的數(shù)據(jù)類型以及數(shù)據(jù)類型的轉(zhuǎn)換
這篇文章主要介紹了JavaScript的數(shù)據(jù)類型以及數(shù)據(jù)類型的轉(zhuǎn)換,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04
JavaScript學(xué)習(xí)筆記之DOM基礎(chǔ)操作實(shí)例小結(jié)
這篇文章主要介紹了JavaScript學(xué)習(xí)筆記之DOM基礎(chǔ)操作,結(jié)合實(shí)例形式總結(jié)分析了javascript針對(duì)dom元素節(jié)點(diǎn)、屬性的相關(guān)獲取、設(shè)置等操作技巧,需要的朋友可以參考下2019-01-01
JavaScript實(shí)現(xiàn)函數(shù)重載的代碼示例
在JavaScript中并沒有直接支持函數(shù)重載的機(jī)制,但是可以通過一些技巧來模擬函數(shù)重載的效果,比如使用參數(shù)判斷,使用默認(rèn)參數(shù),對(duì)象參數(shù),這些方法都可以實(shí)現(xiàn)類似函數(shù)重載的效果,所以本文就給大家介紹一下JavaScript如何實(shí)現(xiàn)函數(shù)重載,需要的朋友可以參考下2023-08-08
如何用JavaScript檢測當(dāng)前瀏覽器是無頭瀏覽器
這篇文章主要介紹了如何用JavaScript檢測當(dāng)前瀏覽器是無頭瀏覽器,對(duì)無頭瀏覽器感興趣的同學(xué),可以參考一下2021-04-04

