Javascript图像处理思路及实现代码


Posted in Javascript onDecember 25, 2012

思路
HTML5的canvas提供了getImageData接口来获取canvas中的数据,所以我们能够先用drawImage接口将图片画在canvas上然后再通过getImageData得到图片数据矩阵。

需要注意,虽然IE9开始支持了canvas接口,但是其getImageData获取的数据并不是以标准的TypedArray方式存储的,或者说IE9没有提供对WebGL Native binary data的支持,所以如果需要对IE9支持,下面的矩阵需要用Array的方式保存。虽然IE9以下版本(例如IE8)有开源项目explorercanvas提供canvas支持,但很可惜G_vmlCanvasManager并没有提供位图数据获取接口。TypedArray的相关内容可以参考HTML5的新数组

基本矩阵
在图像处理中,矩阵计算是非常重要的内容,所以我们首先来建立一个矩阵模型。
通过getImageData接口获取的ImageData虽然具有类似矩阵的结构,但是他的结构是不可变的,不适合扩展,所以我们选择在Javascript中自建一个矩阵。

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 - 代表矩阵的行数
col - 代表矩阵的列数
channel - 代表通道数量,因为通过getImageData获取的图片数据是以RGBA色彩空间进行描述的,即有Red(红)、Green(绿)、Blue(蓝)和Alpha(不透明度)四个通道。
buffer - 数据所用的ArrayBuffer引用。
data - 图片的Uint8ClampedArray数组数据。
bytes - 每个数据单位占用字节,因为是uint8数据类型,所以占用字节数为1。
type - 数据类型是CV_RGBA。
图片数据转成矩阵的方法
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对象,不是字符串URL。因为浏览器中Image的读取是一个异步过程,并不能立刻返回相应的Mat对象,所以这个函数应当这样使用:
var img = new Image(); 
img.onload = function(){ 
var myMat = cv.imread(img); 
}; 
img.src = "1.jpg";

iCtx和iResize方法是一个全局变量,允许给其它函数公用:
var iCanvas = document.createElement("canvas"), 
iCtx = iCanvas.getContext("2d"); 
function iResize(__width, __height){ 
iCanvas.width = __width; 
iCanvas.height = __height; 
}

我们来看一下drawImage方法
用途
在canvas上绘制一个图片。
语法
context.drawImage(img,x,y);
context.drawImage(img,x,y,width,height);
context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height);
例子
还有getImageData方法:
用途
获取canvas中的图像数据。
数据是以RGBA色彩空间返回的,即:
R - 红色通道大小
G - 绿色通道大小
B - 蓝色通道大小
A - 不透明程度大小
语法
context.getImageData(x,y,width,height);
例子
red = imgData.data[0]; 
green = imgData.data[1]; 
blue = imgData.data[2]; 
alpha = imgData.data[3];

矩阵转成图像数据的方法
经过处理后的矩阵,需要一个方法变成ImageData,然后我们就可以通过putImageData方法,在canvas上绘制经过处理的图像了。
function RGBA2ImageData(__imgMat){ 
var width = __imgMat.col, 
height = __imgMat.row, 
imageData = iCtx.createImageData(width, height); 
imageData.data.set(__imgMat.data); 
return imageData; 
}

我们来看一下putImageData方法
用途
通过图像数据,在canvas上绘制图像。
语法
context.putImageData(imgData,x,y,dirtyX,dirtyY,dirtyWidth,dirtyHeight);
将彩色图转换成灰度图
最后我们进行一个简单的色彩空间变换,将图像从RGBA转成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文档中的转换公式
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个通道)对应映射关系应该为:
RGBA to RGBA(GRAY): R1 = G1 = B1 <- 0.299 * R + 0.587 * G + 0.114 * B , A1 <- A
Javascript 相关文章推荐
让iframe子窗体取父窗体地址栏参数(querystring)
Oct 13 Javascript
js中匿名函数的N种写法
Sep 08 Javascript
一个非常全面的javascript URL解析函数和分段URL解析方法
Apr 12 Javascript
jQuery实现视频作为全屏幕背景
Dec 18 Javascript
浅谈javascript实现八大排序
Apr 27 Javascript
JQuery中DOM实现事件移除的方法
Jun 13 Javascript
使用AngularJS制作一个简单的RSS阅读器的教程
Jun 18 Javascript
jquery实现图片上传之前预览的方法
Jul 11 Javascript
JavaScript蒙板(model)功能的简单实现代码
Aug 04 Javascript
AngularJS在IE下取数据总是缓存问题的解决方法
Aug 05 Javascript
Javascript中的作用域及块级作用域
Dec 08 Javascript
JS实现键值对遍历json数组功能示例
May 30 Javascript
javascript的offset、client、scroll使用方法详解
Dec 25 #Javascript
JS解析json数据并将json字符串转化为数组的实现方法
Dec 25 #Javascript
jquery 事件冒泡的介绍以及如何阻止事件冒泡
Dec 25 #Javascript
js优化针对IE6.0起作用(详细整理)
Dec 25 #Javascript
js 取时间差去掉周六周日实现代码
Dec 25 #Javascript
纯js网页画板(Graphics)类简介及实现代码
Dec 24 #Javascript
Knockoutjs快速入门(经典)
Dec 24 #Javascript
You might like
用php实现批量查询清除一句话后门的代码
2008/01/20 PHP
PHP获取一个字符串中间一部分字符的方法
2014/08/19 PHP
四个常见html网页乱码问题及解决办法
2015/09/08 PHP
javascript 函数调用的对象和方法
2010/07/01 Javascript
深入理解jQuery中live与bind方法的区别
2013/12/18 Javascript
判断客户浏览器是否支持cookie的示例代码
2013/12/23 Javascript
自写的jQuery异步加载数据添加事件
2014/05/15 Javascript
JS实现常见的TAB、弹出层效果(TAB标签,斑马线,遮罩层等)
2015/10/08 Javascript
微信小程序 获取当前地理位置和经纬度实例代码
2016/12/05 Javascript
AngularJS中的缓存使用
2017/01/11 Javascript
jquery插件ContextMenu设置右键菜单
2017/03/13 Javascript
浅谈vuepress 踩坑记
2018/04/18 Javascript
Vue-cli@3.0 插件系统简析
2018/09/05 Javascript
详解vue中的computed的this指向问题
2018/12/05 Javascript
JS module的导出和导入的实现代码
2019/02/25 Javascript
微信小程序实现页面浮动导航
2020/01/08 Javascript
[08:56]DOTA2-DPC中国联赛2月23日Recap集锦
2021/03/11 DOTA
python 全文检索引擎详解
2017/04/25 Python
浅谈django model的get和filter方法的区别(必看篇)
2017/05/23 Python
python pytest进阶之conftest.py详解
2019/06/27 Python
Django时区详解
2019/07/24 Python
解决matplotlib.pyplot在Jupyter notebook中不显示图像问题
2020/04/22 Python
Python venv虚拟环境配置过程解析
2020/07/08 Python
解决html5中video标签无法播放mp4问题的办法
2017/05/07 HTML / CSS
澳大利亚领先的在线葡萄酒零售商:Get Wines Direct
2018/03/27 全球购物
软件工程师面试题
2012/06/25 面试题
项目采购员岗位职责
2014/04/15 职场文书
语文教育专业求职信
2014/06/28 职场文书
意向书范本
2014/07/29 职场文书
社区护士演讲稿
2014/08/27 职场文书
工作会议通知
2015/04/15 职场文书
安全教育第一课观后感
2015/06/17 职场文书
狂人日记读书笔记
2015/06/30 职场文书
初一军训感言
2015/08/01 职场文书
导游词之岳阳楼
2019/09/25 职场文书
Mysql多层子查询示例代码(收藏夹案例)
2022/03/31 MySQL