本文主题

情人节在网上看到国外JS牛人利用HTML5技术实现的一朵玫瑰花,深切的感受到HTML5技术的强大。本着学习的态度看了一下那朵玫瑰花的源代码,其中用到的HTML5技术是canvas标签,于是灵光一现,想试一下能不能进行图像处理,结果成功了,再次介绍一下经验。

本文的思路是获取一张带有验证码的图片,然后对其进行灰度化操作,完成后对其使用Otsu算法进行二值化操作,最后输出二值化的图片,其效果图如下:

图1

最后友情提醒一下,HTML5技术在IE浏览器下面不支持或者是没有全面支持,因此如要进行HTML5开发请使用火狐或者是谷歌等支持的浏览器。

显示图像

在页面中引入canvas标签,并设置其id属性,在脚本中使用getElementById()来获取标签的句柄。

function drawImage(){
//获取标签的句柄
var canvas = document.getElementById('myCanvasElt');
//获取绘图的上下文
var ctx = canvas.getContext('2d');
//新建一个image,目的是为了读取图片
var img=new Image()
img.src="data:image/VerifyCode.jpg"
//将image中的图片绘制到canvas中
ctx.drawImage(img,0,0);
}

以上代码实现了图1中原图像的显示。

灰值化图像

对图像进行灰值化的过程就是将一幅图像的RGB三个属性设为一致的过程,即去掉图像的颜色信息,使用灰度信息表达图像的内容。彩色转灰度图像有几种算法:

1.加权平均法。Gray = R*0.299 + G*0.587 + B*0.114

2.平均值法。Gray = ( R + G + B )/3

3.最大值法。Gray  = Max(R,G,B)

其中R,G,B表示图像三个分量的值,上述三种算法的好坏对比在这里不做解释,详细资料请参阅彩色图像灰度化。本文采用第一种方法。

//彩色图像灰度化
function ProcessToGrayImage(){
	var canvas = document.getElementById('myCanvasElt');
	var ctx = canvas.getContext('2d');
	//取得图像数据
        var canvasData = ctx.getImageData(0, 0, canvas.width, canvas.height);
	//这个循环是取得图像的每一个点,在计算灰度后将灰度设置给原图像
        for (var x = 0; x < canvasData.width; x++) {
	    for (var y = 0; y < canvasData.height; y++) {
	        // Index of the pixel in the array
	        var idx = (x + y * canvas.width) * 4;
	        // The RGB values
	        var r = canvasData.data[idx + 0];
	        var g = canvasData.data[idx + 1];
	        var b = canvasData.data[idx + 2];
	        //更新图像数据
	        var gray = CalculateGrayValue(r , g , b);
	        canvasData.data[idx + 0] = gray;
	        canvasData.data[idx + 1] = gray;
	        canvasData.data[idx + 2] = gray;
	    }
	}
	ctx.putImageData(canvasData, 0, 0);
}
//计算图像的灰度值,公式为:Gray = R*0.299 + G*0.587 + B*0.114
 function CalculateGrayValue(rValue,gValue,bValue){
 	   return parseInt(rValue * 0.299 + gValue * 0.587 + bValue * 0.114);
 	}	

Otsu算法

关于Otsu算法的具体理论在这里不再讲解。这是一种二值化速度很快的图像分割算法。后面会把该算法的理论详细说明。使用javascript算法实现的过程如下:

//一维OTSU图像处理算法
 function OTSUAlgorithm(){
   var m_pFstdHistogram = new Array();//表示灰度值的分布点概率
   var m_pFGrayAccu = new Array();//其中每一个值等于m_pFstdHistogram中从0到当前下标值的和
   var m_pFGrayAve = new Array();//其中每一值等于m_pFstdHistogram中从0到当前指定下标值*对应的下标之和
   var m_pAverage=0;//值为m_pFstdHistogram【256】中每一点的分布概率*当前下标之和
   var m_pHistogram = new Array();//灰度直方图
   var i,j;
   var temp=0,fMax=0;//定义一个临时变量和一个最大类间方差的值
   var nThresh = 0;//最优阀值
   //获取灰度图像的信息
   var imageInfo = GetGrayImageInfo();
   if(imageInfo == null){
     window.alert("图像还没有转化为灰度图像!");
     return;
   }
   //初始化各项参数
   for(i=0; i<256; i++){
     m_pFstdHistogram[i] = 0;
     m_pFGrayAccu[i] = 0;
     m_pFGrayAve[i] = 0;
     m_pHistogram[i] = 0;
   }
   //获取图像信息
   var canvasData = imageInfo[0];
   //获取图像的像素
   var pixels = canvasData.data;
   //下面统计图像的灰度分布信息
   for(i=0; i<pixels.length; i+=4){
      //获取r的像素值,因为灰度图像,r=g=b,所以取第一个即可
      var r = pixels[i];
      m_pHistogram[r]++;
   }
   //下面计算每一个灰度点在图像中出现的概率
   var size = canvasData.width * canvasData.height;
   for(i=0; i<256; i++){
      m_pFstdHistogram[i] = m_pHistogram[i] / size;
   }
   //下面开始计算m_pFGrayAccu和m_pFGrayAve和m_pAverage的值
   for(i=0; i<256; i++){
      for(j=0; j<=i; j++){
        //计算m_pFGaryAccu[256]
		m_pFGrayAccu[i] += m_pFstdHistogram[j];
		//计算m_pFGrayAve[256]
		m_pFGrayAve[i] += j * m_pFstdHistogram[j];
      }
      //计算平均值
	  m_pAverage += i * m_pFstdHistogram[i];
   }
   //下面开始就算OSTU的值,从0-255个值中分别计算ostu并寻找出最大值作为分割阀值
   for (i = 0 ; i < 256 ; i++){
		temp = (m_pAverage * m_pFGrayAccu[i] - m_pFGrayAve[i])
		     * (m_pAverage * m_pFGrayAccu[i] - m_pFGrayAve[i])
		     / (m_pFGrayAccu[i] * (1 - m_pFGrayAccu[i]));
		if (temp > fMax)
		{
			fMax = temp;
			nThresh = i;
		}
	}
   //下面执行二值化过程
   for(i=0; i<canvasData.width; i++){
      for(j=0; j<canvasData.height; j++){
         //取得每一点的位置
         var ids = (i + j*canvasData.width)*4;
         //取得像素的R分量的值
         var r = canvasData.data[ids];
         //与阀值进行比较,如果小于阀值,那么将改点置为0,否则置为255
         var gray = r>nThresh?255:0;
         canvasData.data[ids+0] = gray;
         canvasData.data[ids+1] = gray;
         canvasData.data[ids+2] = gray;
      }
   }
   //显示二值化图像
   var newImage = document.getElementById('myCanvasThreshold').getContext('2d');
   newImage.putImageData(canvasData,0,0);
 }

 //获取图像的灰度图像的信息
 function GetGrayImageInfo(){
    var canvas = document.getElementById('myCanvasElt');
	var ctx = canvas.getContext('2d');
	var canvasData = ctx.getImageData(0, 0, canvas.width, canvas.height);
	if(canvasData.data.length==0){
	  return null;
	}
	return [canvasData,ctx];
 }
 //下面对灰度图像进行处理,将目标信息分割出来
 function DividedTarget(){
   //读取二值化图像信息
   var imageInfo = document.getElementById('myCanvasThreshold');
   if(imageInfo == null){
     window.alert("没有发现二值化图像信息!");
     return;
   }
   //取得上下文
   var ctx = imageInfo.getContext('2d');
   //获取图像数据
   var canvasData = imageInfo.getImageData(0, 0, ctx.width, ctx.height);
   var newVanvasData = canvasData;
   //取得图像的宽和高
   var width = canvasData.width;
   var height = canvasData.height;
   //算法开始
   var cursor = 2;
   for(var x=0; x<width; x++){
      for(var y=0; y<height; y++){
         //取得每一点的位置
         var ids = (x + y*canvasData.width)*4;
         //取得像素的R分量的值
         var r = canvasData.data[ids];
         //如果是目标点
         if(r==0){

         }
      }
   }

 }

算法的实现中给出了详细的注释,如果有不清楚的地方可以留言或者发邮件咨询,值得注意的是,由于js不允许跨域访问的特性,要想成功运行上面的代码,必须将它运行在一个服务器中,比如说Apache。

代码详单

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>gray.html</title>

    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="this is my page">
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">

    <!--<link rel="stylesheet" type="text/css" href="./styles.css">-->
<script type="text/javascript">
function ProcessToGrayImage(){
	var canvas = document.getElementById('myCanvasElt');
	var ctx = canvas.getContext('2d');
	var img=new Image()
	img.src="data:image/VerifyCode.jpg"
	ctx.drawImage(img,0,0);

	var canvasData = ctx.getImageData(0, 0, canvas.width, canvas.height);
	for (var x = 0; x < canvasData.width; x++) {
	    for (var y = 0; y < canvasData.height; y++) {
	        // Index of the pixel in the array
	        var idx = (x + y * canvas.width) * 4;
	        // The RGB values
	        var r = canvasData.data[idx + 0];
	        var g = canvasData.data[idx + 1];
	        var b = canvasData.data[idx + 2];
	        // Update the values of the pixel;
	        var gray = CalculateGrayValue(r , g , b);
	        canvasData.data[idx + 0] = gray;
	        canvasData.data[idx + 1] = gray;
	        canvasData.data[idx + 2] = gray;
	    }
	}
	ctx.putImageData(canvasData, 0, 0);
}
//计算图像的灰度值,公式为:Gray = R*0.299 + G*0.587 + B*0.114
 function CalculateGrayValue(rValue,gValue,bValue){
 	   return parseInt(rValue * 0.299 + gValue * 0.587 + bValue * 0.114);
 	}
 //一维OTSU图像处理算法
 function OTSUAlgorithm(){
   var m_pFstdHistogram = new Array();//表示灰度值的分布点概率
   var m_pFGrayAccu = new Array();//其中每一个值等于m_pFstdHistogram中从0到当前下标值的和
   var m_pFGrayAve = new Array();//其中每一值等于m_pFstdHistogram中从0到当前指定下标值*对应的下标之和
   var m_pAverage=0;//值为m_pFstdHistogram【256】中每一点的分布概率*当前下标之和
   var m_pHistogram = new Array();//灰度直方图
   var i,j;
   var temp=0,fMax=0;//定义一个临时变量和一个最大类间方差的值
   var nThresh = 0;//最优阀值
   //获取灰度图像的信息
   var imageInfo = GetGrayImageInfo();
   if(imageInfo == null){
     window.alert("图像还没有转化为灰度图像!");
     return;
   }
   //初始化各项参数
   for(i=0; i<256; i++){
     m_pFstdHistogram[i] = 0;
     m_pFGrayAccu[i] = 0;
     m_pFGrayAve[i] = 0;
     m_pHistogram[i] = 0;
   }
   //获取图像信息
   var canvasData = imageInfo[0];
   //获取图像的像素
   var pixels = canvasData.data;
   //下面统计图像的灰度分布信息
   for(i=0; i<pixels.length; i+=4){
      //获取r的像素值,因为灰度图像,r=g=b,所以取第一个即可
      var r = pixels[i];
      m_pHistogram[r]++;
   }
   //下面计算每一个灰度点在图像中出现的概率
   var size = canvasData.width * canvasData.height;
   for(i=0; i<256; i++){
      m_pFstdHistogram[i] = m_pHistogram[i] / size;
   }
   //下面开始计算m_pFGrayAccu和m_pFGrayAve和m_pAverage的值
   for(i=0; i<256; i++){
      for(j=0; j<=i; j++){
        //计算m_pFGaryAccu[256]
		m_pFGrayAccu[i] += m_pFstdHistogram[j];
		//计算m_pFGrayAve[256]
		m_pFGrayAve[i] += j * m_pFstdHistogram[j];
      }
      //计算平均值
	  m_pAverage += i * m_pFstdHistogram[i];
   }
   //下面开始就算OSTU的值,从0-255个值中分别计算ostu并寻找出最大值作为分割阀值
   for (i = 0 ; i < 256 ; i++){
		temp = (m_pAverage * m_pFGrayAccu[i] - m_pFGrayAve[i])
		     * (m_pAverage * m_pFGrayAccu[i] - m_pFGrayAve[i])
		     / (m_pFGrayAccu[i] * (1 - m_pFGrayAccu[i]));
		if (temp > fMax)
		{
			fMax = temp;
			nThresh = i;
		}
	}
   //下面执行二值化过程
   for(i=0; i<canvasData.width; i++){
      for(j=0; j<canvasData.height; j++){
         //取得每一点的位置
         var ids = (i + j*canvasData.width)*4;
         //取得像素的R分量的值
         var r = canvasData.data[ids];
         //与阀值进行比较,如果小于阀值,那么将改点置为0,否则置为255
         var gray = r>nThresh?255:0;
         canvasData.data[ids+0] = gray;
         canvasData.data[ids+1] = gray;
         canvasData.data[ids+2] = gray;
      }
   }
   //显示二值化图像
   var newImage = document.getElementById('myCanvasThreshold').getContext('2d');
   newImage.putImageData(canvasData,0,0);
 }

 //获取图像的灰度图像的信息
 function GetGrayImageInfo(){
    var canvas = document.getElementById('myCanvasElt');
	var ctx = canvas.getContext('2d');
	var canvasData = ctx.getImageData(0, 0, canvas.width, canvas.height);
	if(canvasData.data.length==0){
	  return null;
	}
	return [canvasData,ctx];
 }
 //下面对灰度图像进行处理,将目标信息分割出来
 function DividedTarget(){
   //读取二值化图像信息
   var imageInfo = document.getElementById('myCanvasThreshold');
   if(imageInfo == null){
     window.alert("没有发现二值化图像信息!");
     return;
   }
   //取得上下文
   var ctx = imageInfo.getContext('2d');
   //获取图像数据
   var canvasData = imageInfo.getImageData(0, 0, ctx.width, ctx.height);
   var newVanvasData = canvasData;
   //取得图像的宽和高
   var width = canvasData.width;
   var height = canvasData.height;
   //算法开始
   var cursor = 2;
   for(var x=0; x<width; x++){
      for(var y=0; y<height; y++){
         //取得每一点的位置
         var ids = (x + y*canvasData.width)*4;
         //取得像素的R分量的值
         var r = canvasData.data[ids];
         //如果是目标点
         if(r==0){

         }
      }
   }

 }
</script>
  </head>

  <body>
  原图像:<br/>
  <img src="data:image/VerifyCode.jpg" /><br/>
  灰度图像:<input type="button" value="处理" onclick="javascript:ProcessToGrayImage();" /><br/>
  <canvas id="myCanvasElt" width="200" height="100"></canvas><br/>
  二值化图像:<input type="button" value="二值化" onclick="javascript:OTSUAlgorithm();" /><br/>
  <canvas id="myCanvasThreshold" width="200" height="100"></canvas><br/>
  </body>
</html>

总结说明

html5图像、图片处理【转】的更多相关文章

  1. HTML5将图片转化成字符画

    HTML5将图片转化成字符画 字符画大家一定非常熟悉了,那么如何把一张现有的图片转成字符画呢?HTML5让这个可能变成了现实,通过canvas,可以很轻松实现这个功能.其实原理很简单:扫描图片相应位置 ...

  2. Atitit.计算机图形图像图片处理原理与概论attilax总结

    Atitit.计算机图形图像图片处理原理与概论attilax总结 计算机图形1 图像处理.分析与机器视觉(第3版)1 数字图像处理(第六版)2 图像处理基础(第2版)2 发展沿革 1963年,伊凡·苏 ...

  3. 9个超绚丽的HTML5 3D图片动画特效

    在Web 1.0时代,我们的网页中图片数量非常少,而且都是以静态图片为主.HTML5的出现,推动了Web 2.0的发展,同时也催生出了很多绚丽的HTML5图片动画特效,特别是有些还有3D的动画效果.本 ...

  4. 10款让人惊叹的HTML5/jQuery图片动画特效

    1.HTML5相册照片浏览器 可连接Flickr照片服务 以前我们经常会分享一些jQuery相册浏览插件,效果不错,实用性也很强.不过如果能利用HTML5来实现相册浏览器,那么相册浏览效果肯定会更加炫 ...

  5. Html5选择图片并及时预览图片

    以往想要实现图片预览基本都是先传至服务器后等返回链接地址才能进行预览,使用Html5选择图片并及时预览图片的代码如下,使用起来更爽了. <!DOCTYPE html> <html l ...

  6. HTML5动画图片播放器 高端大气

    我们见过很多图片播放插件(焦点图),很多都基于jQuery.今天介绍的HTML5图片播放器很特别,它不仅在图片间切换有过渡动画效果,而且在切换时图片中的元素也将出现动画效果,比如图中的文字移动.打散. ...

  7. HTML5实现图片文件异步上传

    原文:HTML5实现图片文件异步上传 利用HTML5的新特点做文件异步上传非常简单方便,本文主要展示JS部分,html结构.下面的代码并未使用第三发库,如果有参照,请注意一些未展现出来的代码片段.我这 ...

  8. html5中将图片的绝对路径转换成文件对象

    html5中将图片的绝对路径转换成文件对象 将图片的绝对路径转换成base64编码,请看这篇文章 我们先来理解基本知识点: 1. 理解HTML5中的FileList对象与file对象. 在HTML5中 ...

  9. 基于html5背景图片自适应代码

    基于html5背景图片自适应代码是一款背景不随滚动条滚动,会根据分辨率不同自动匹配对应的背景图片.效果图如下: 在线预览   源码下载 实现的代码. css代码: .jawbone-hero .jaw ...

  10. HTML5裁剪图片并上传至服务器实现原理讲解

    HTML5裁剪图片并上传至服务器实现原理讲解   经常做项目需要本地上传图片裁剪并上传服务器,比如会议头像等功能,但以前实现这类需求都很复杂,往往需要先把图片上传到服务器,然后返回给用户,让用户确定裁 ...

随机推荐

  1. Sublime Text的使用技巧

    来到腾讯之后,基本上整个团队都在使用Sublime Text这款编辑神器.虽说自己以前在写python的时候略有接触过,但只是把它当做简单的文本编辑器.来到这边后,才逐渐的体会到这款神作的牛逼之处. ...

  2. PHP函数usort是咋回事?还能当后门?

    开始 详情看这:https://www.leavesongs.com/PHP/bypass-eval-length-restrict.html 原谅我见识短,没用过usort函数 上面连接的文章中,发 ...

  3. 较有意思的Apple XSS(CVE-2016-7762)漏洞

    文章作者:Avfisher0x00 前言应CVE作者的要求帮忙分析一下这个漏洞,实际上这是一个思路比较有意思的Apple XSS(CVE-2016-7762).漏洞作者确实脑洞比较大也善于尝试和发掘, ...

  4. lightoj 1296 - Again Stone Game 博弈论

    思路:由于数据很大,先通过打表找规律可以知道, 当n为偶数的时候其SG值为n/2; 当n为奇数的时候一直除2,直到为偶数m,则SG值为m/2; 代码如下: #include<stdio.h> ...

  5. [BZOJ1005](HNOI 2008)明明的烦恼

    Description 自从明明学了树的结构,就对奇怪的树产生了兴趣...... 给出标号为1到N的点,以及某些点最终的度数,允许在任意两点间连线,可产生多少棵度数满足要求的树? Input 第一行为 ...

  6. 快速幂 cojs 1130. 取余运算

    cojs 1130. 取余运算 ★   输入文件:dmod.in   输出文件:dmod.out   简单对比时间限制:10 s   内存限制:128 MB [题目描述] 输入b,p,k的值,求b^p ...

  7. 在WPF中快速实现键盘钩子

    大部分的时候,当我们需要键盘事件的时候,可以通过在主窗口注册KeyBinding来实现,不过,有的时候我们需要的是全局键盘事件,想在任何一个地方都能使用,最开始的时候我是通过键盘钩子来实现的, 不过键 ...

  8. Boost Converter

    Single Inductor Buck-Boost Converter in Tiny WCSP The TPS63036 is a non inverting buck-boost convert ...

  9. java开发常用的Linux命令

    原文:https://www.cnblogs.com/not-alone/p/8505925.html 1.查找文件 find / -name filename.txt 根据名称查找/目录下的file ...

  10. [mark]如何删除地址栏的记录?

    比如,我输入字母a ..因为经常访问.它首先会自动帮我补填 amazon.cn 第二行出现 ali213...第三行是 alipay... 这个很简单,没必要搞得很复杂很Geek.比如楼主的情况,首先 ...