19.基本图像效果

修改像素的颜色值并不意味着必须从零开始创建整个图像,已经存在的图像也是可以修改的。有一个例子就是基本照片处理——通过修改图像中的像素来修改它的显示效果。这种效果在画布中实现是很简单的,特别是现在你已经掌握了像素的操作方法。

反转颜色

这个效果将反转图像的颜色值,这会使它看起来有些奇怪(找不到更适合的词来形容)。基本方法就是用255减去像素现在的颜色值(150),所得的就是反转后的颜色(255-150=105)。让我们尝试一些不同的操作,然后看看最后的代码,这里并没有新知识。

 var image = new Image(); 
image.src = "example.jpg"; 
    $(image).load(function() { 
        context.drawImage(image, 0, 0, 1024, 683, 0, 0, 500, 500);
        var imageData = context.getImageData(0, 0, canvas.width(), canvas.height()); 
        var pixels = imageData.data; 
        var numPixels = pixels.length; 
        context.clearRect(0, 0, canvas.width(), canvas.height()); 
        for (var i = 0; i < numPixels; i++) { 
            pixels[i*4] = 255-pixels[i*4]; // Red
            pixels[i*4+1] = 255-pixels[i*4+1]; // Green
            pixels[i*4+2] = 255-pixels[i*4+2]; // Blue
        };
    context.putImageData(imageData, 0, 0); 
}); 

前面几行代码创建了一个新的Image对象,然后加载上一节使用的示例图像。等到图像加载完成之后,将图像绘制到画布上,并将包含所有像素的ImageData对象保存到一个变量中。在保存了像素之后,清除画布,开始循环处理原始图像中所有的像素。

在循环中,我们使用与上一节中第一个例子(红色正方形)相同的方法来防问像素,并用255减去当前值。不需要对阿尔法值进行任何处理,因为我们要保留原始图像中的这个值。

最后是将像素绘制回画布,这样就得到一个反转颜色的图像(参见图1)。

图1 反转图像的颜色

灰度

另一个有趣的效果是灰度,这也许是更有用的一种效果。将彩色图像变为灰色(有时候也称为黑白色,但是这种说法并不准确),除了访问和修改颜色值,实现代码与反转颜色例子中的代码完全相同。

 for (var i = 0; i < numPixels; i++) { 
    var average = (pixels[i*4]+pixels[i*4+1]+pixels[i*4+2])/3; 
    pixels[i*4] = average; // Red 
    pixels[i*4+1] = average; // Green
    pixels[i*4+2] = average; // Blue 
}; 

将彩色转换为灰度要求计算出现有颜色值的平均值,即将它们加在一起然后除以颜色个数。这个平均颜色将作为三种颜色(红、绿和蓝)的值。其结果是将每一种颇色转换为灰度(参见图2)。

图2 将图像转换为灰度

像素化

你是否曾经看到过新闻或文件中人物脸孔被像素化的情况?这是一种强大的特效,它可以将图像变得不可识别,但并不真正删除整个部分。实际上重新在画布上创建会相对简单一些,只需要将图像按栅格分割,或者对每个片段的颜色取平均值,或者选取每个片段的颜色。我们将使用的代码与上一节马赛克的例子很相似。

var image = new Image(); 
image.src = "example.jpg"; 
    $(image).load(function() { 
    context.drawImage(image, 0, 0, 1024, 683, 0, 0, 500, 500); 
    var imageData = context.getImageData(0, 0, canvas.width(), canvas.height()); 
    var pixels = imageData.data; 
    context.clearRect(0, 0, canvas.width(), canvas.height()); 
    
                            var numTileRows = 20; 
    var numTileCols = 20; 
    var tileWidth = imageData.width/numTileCols; 
    var tileHeight = imageData.height/numTileRows; 
    
    for (var r = 0; r < numTileRows; r++) { };
}); 

循环之前的代码都是一样的。访问图像,等待图像加载,将它绘制到画布中,保存ImageData对象,从画布清除该图像,然后给分割的图像赋值确定块(片段)的数量和尺寸。

这两个循环的工作方式与马赛克的例子是一样的:第一个循环处理每一行块,第二个循环则处理当前行中的每一个块。而新的代码位于循环中,访问颜色值和创建像素化效果。

这里将使用第二种方法来获取像素化效果的颜色值,为每一个块选择一种颜色。最简单的方法是使用块的中心位置像素,将以下代码添加到第二个循环中,就可以得到这个信息:

var x = (c*tileWidth)+(tileWidth/2); 
var y = (r*tileHeight)+(tileHeight/2); 
var pos = (Math.floor(y)*(imageData.width*4))+(Math.floor(x)*4); 

前两行将得到当前块中心像素从0开始表示的(x,y)坐标。这个计算方法与马赛克例子非常相似,先找到块边缘的(x,y)坐标位置,然后加上一半宽度或高度,从而确定中心。然后将(x,y)坐标传入标准公式,这样就得到CanvasPixelArray中该像素的索引值.但你可能注意到了,(x,y)坐标值在Math对象的floor方法中进行了取整处理。其原因是,除(x,y)是整数,否则这个返回的索引将是错误的,所以我们使用floor方法将值取整为下一个最小整数(侧如,3.567取整后变成3)。

最后,我们得到了访问颜色值和绘制像素化效果所需要的全部信息。将下面的代码插入到变量pos的声明语句之后。

 var red = pixels[pos]; var green = pixels[pos+1]; 
var blue = pixels[pos+2]; 
context.fillStyle = "rgb("+red+", "+green+", "+blue+")"; 
context.fillRect(x-(tileWidth/2), y-(tileHeight/2), tileWidth, tileHeight); 

这里没有新代码,它只是访问红色、绿色和蓝色值,然后使用这些值来设置fillStyle。最后一步是在块的位置上绘制一个正方形,它是使用所访问的颜色填充的。结果是将示例图像变成一个独特的像素化效果(参见图3)。

图3 使用画布实现图像像素化

我们可以进一步将正方形修改为圆形(参见图4)。

context.beginPath(); 
context.arc(x, y, tileWidth/2, 0, Math.PI*2, false); 
context.closePath(); 
context.fill(); 

现在效果更酷了!

图4 在画布中使用圆形替换正方形实现图像像素化
文件下载(已下载 2677 次)

发布时间:2013/2/3 下午8:54:31  阅读次数:7130

2006 - 2024,推荐分辨率 1024*768 以上,推荐浏览器 Chrome、Edge 等现代浏览器,截止 2021 年 12 月 5 日的访问次数:1872 万 9823 站长邮箱

沪 ICP 备 18037240 号-1

沪公网安备 31011002002865 号