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 相关文章推荐
在JS数组特定索引处指定位置插入元素的技巧
Aug 24 Javascript
Js 正则表达式知识汇总
Dec 02 Javascript
jQuery的观察者模式详解
Dec 22 Javascript
JavaScript中的splice方法用法详解
Jul 20 Javascript
如何判断出一个js对象是否一个dom对象
Nov 24 Javascript
jquery实现简单的瀑布流布局
Dec 11 Javascript
jQuery插件echarts实现的单折线图效果示例【附demo源码下载】
Mar 04 Javascript
Vue.js实战之通过监听滚动事件实现动态锚点
Apr 04 Javascript
jquery实现下拉菜单的手风琴效果
Jul 23 jQuery
使用VueRouter的addRoutes方法实现动态添加用户的权限路由
Jun 03 Javascript
pageGroup.js实现分页功能
Jul 27 Javascript
js实现电灯开关效果
Jan 19 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
从一个不错的留言本弄的mysql数据库操作类
2007/09/02 PHP
php实现与erlang的二进制通讯实例解析
2014/07/23 PHP
Nginx下配置codeigniter框架方法
2015/04/07 PHP
php 中phar包的使用教程详解
2018/10/26 PHP
使用 PHP Masked Package 屏蔽敏感数据的实现方法
2019/10/15 PHP
静态页面的值传递(三部曲)
2006/09/25 Javascript
javascript css在IE和Firefox中区别分析
2009/02/18 Javascript
jquery form表单提交插件asp.net后台中文解码
2010/06/12 Javascript
用js替换除数字与逗号以外的所有字符的代码
2014/06/07 Javascript
javascript面向对象快速入门实例
2015/01/13 Javascript
jQuery中offsetParent()方法用法实例
2015/01/19 Javascript
详解jQuery UI库中文本输入自动补全功能的用法
2016/04/23 Javascript
图文详解JavaScript的原型对象及原型链
2016/08/02 Javascript
JS实现表单多文件上传样式美化支持选中文件后删除相关项
2016/09/30 Javascript
利用JS轻松实现获取表单数据
2016/12/06 Javascript
JS正则表达式学习之贪婪和非贪婪模式实例总结
2016/12/26 Javascript
bootstrap jquery dataTable 异步ajax刷新表格数据的实现方法
2017/02/10 Javascript
js的OOP继承实现(必看篇)
2017/02/18 Javascript
React 使用Hooks简化受控组件的状态绑定
2019/03/18 Javascript
原生js实现的金山打字小游戏(实例代码详解)
2020/03/16 Javascript
基于jquery实现彩色投票进度条代码解析
2020/08/26 jQuery
Vue 组件注册全解析
2020/12/17 Vue.js
[02:04]2014DOTA2国际邀请赛 BBC小组赛第三天总结
2014/07/12 DOTA
python继承和抽象类的实现方法
2015/01/14 Python
Python使用Flask框架获取当前查询参数的方法
2015/03/21 Python
linux平台使用Python制作BT种子并获取BT种子信息的方法
2017/01/20 Python
Python简单生成8位随机密码的方法
2017/05/24 Python
Python实现读写sqlite3数据库并将统计数据写入Excel的方法示例
2017/08/07 Python
Python编程使用*解包和itertools.product()求笛卡尔积的方法
2017/12/18 Python
Python开发的十个小贴士和技巧及长常犯错误
2018/09/27 Python
Python基于Socket实现简易多人聊天室的示例代码
2020/11/29 Python
海信商城:海信电视、科龙空调、容声冰箱官方专卖
2017/02/07 全球购物
幼儿园六一亲子活动方案
2014/08/26 职场文书
党员三严三实心得体会
2014/10/13 职场文书
餐厅服务员管理制度
2015/08/05 职场文书
Element-ui Layout布局(Row和Col组件)的实现
2021/12/06 Vue.js