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 相关文章推荐
javascript css float属性的特殊写法
Nov 13 Javascript
常用简易JavaScript函数
Apr 09 Javascript
javascript 延迟加载技术(lazyload)简单实现
Jan 17 Javascript
JS操作Cookies的小例子
Oct 15 Javascript
javascript实现滑动解锁功能
Dec 31 Javascript
js制作可以延时消失的菜单
Jan 13 Javascript
JS查找字符串中出现最多的字符及个数统计
Feb 04 Javascript
JavaScript中三个等号和两个等号你了解多少
Jul 04 Javascript
js canvas实现简单的图像扩散效果
Jun 28 Javascript
JS实现判断图片是否加载完成的方法分析
Jul 31 Javascript
JQuery实现简单的复选框树形结构图示例【附源码下载】
Jul 16 jQuery
js实现鼠标滑动到某个div禁止滚动
Sep 17 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使用fopen与file_get_contents读取文件实例分享
2016/03/04 PHP
PHP加密技术的简单实现
2016/09/04 PHP
php的api数据接口书写实例(推荐)
2016/09/22 PHP
PHP中通过getopt解析GNU C风格命令行选项
2019/11/18 PHP
JavaScript 学习笔记(七)字符串的连接
2009/12/31 Javascript
JS图片无缝、平滑滚动代码
2014/03/11 Javascript
DOM基础教程之使用DOM控制表格
2015/01/20 Javascript
JavaScript精炼之构造函数 Constructor及Constructor属性详解
2015/11/05 Javascript
超实用的JavaScript代码段 附使用方法
2016/05/22 Javascript
JavaScript基础语法之js表达式
2016/06/07 Javascript
jquery判断iPhone、Android设备类型
2016/09/14 Javascript
jquery仿苹果的时间/日期选择效果
2017/03/08 Javascript
js实现股票实时刷新数据案例
2017/05/14 Javascript
jQuery简单判断值是否存在于数组中的方法示例
2018/04/17 jQuery
微信小程序WebSocket实现聊天对话功能
2018/07/06 Javascript
vue+web端仿微信网页版聊天室功能
2019/04/30 Javascript
利用Vue实现一个markdown编辑器实例代码
2019/05/19 Javascript
vue轮播组件实现$children和$parent 附带好用的gif录制工具
2019/09/26 Javascript
Vue vm.$attrs使用场景详解
2020/03/08 Javascript
基于JavaScript实现控制下拉列表
2020/05/08 Javascript
[01:03:41]DOTA2-DPC中国联赛 正赛 Dynasty vs XG BO3 第三场 2月2日
2021/03/11 DOTA
在python中的socket模块使用代理实例
2014/05/29 Python
解决在pycharm中显示额外的 figure 窗口问题
2019/01/15 Python
python广度优先搜索得到两点间最短路径
2019/01/17 Python
pyqt实现.ui文件批量转换为对应.py文件脚本
2019/06/19 Python
使用Django搭建web服务器的例子(最最正确的方式)
2019/08/29 Python
Python数学形态学实例分析
2019/09/06 Python
通过python扫描二维码/条形码并打印数据
2019/11/14 Python
深入浅析python变量加逗号,的含义
2020/02/22 Python
Pandas实现一列数据分隔为两列
2020/05/18 Python
如何使用python记录室友的抖音在线时间
2020/06/29 Python
《鸿门宴》教学反思
2014/04/22 职场文书
跳高加油稿
2015/07/21 职场文书
数学备课组工作总结
2015/08/12 职场文书
详解Redis实现限流的三种方式
2021/04/27 Redis
Android Studio实现带三角函数对数运算功能的高级计算器
2022/05/20 Java/Android