本文转载自blog

转载请注明出处

前言

黑白照片的时代虽然已经过去,但现在看到以前的照片,是不是有一种回到过去的感觉,很cool有木有~
看完这篇文章,就可以把彩色照片变成各种各样的黑白的照片啦。

本文完整的在线例子图片灰度算法例子,例子的图片有点多,可能有些慢。

例子的源码位于blog/demo里

三原色与灰度

原色是指不能透过其他颜色的混合调配而得出的“基本色”。一般来说叠加型的三原色是红色绿色蓝色,以不同比例将原色混合,可以产生出其他的新颜色。这套原色系统常被称为“RGB色彩空间”,亦即由红(R)绿(G)蓝(B)所组合出的色彩系统。

当这三种原色以等比例叠加在一起时,会变成灰色;若将此三原色的强度均调至最大并且等量重叠时,则会呈现白色。灰度就是没有色彩,RGB色彩分量全部相等。

获取图片的像素数据

算法不区分语言,这里以前端举例。可以使用canvas取得图片某个区域的像素数据

//伪代码
var img = new Image();
img.src = 'xxx.jpg';
var myCanvas = document.querySelector(canvasId);
var canvasCtx = myCanvas.getContext("2d");
canvasCtx.drawImage(img, 0, 0, img.width, img.height);
//图片的像素数据
var data = canvasCtx.getImageData(0, 0, img.width, img.height);

使用getImageData()返回一个ImageData对象,此对象有个data属性就是我们要的数据了,数据是以Uint8ClampedArray 描述的一个一维数组,包含以 RGBA 顺序的数据,数据使用 0 至 255(包含)的整数表示。 所以,一个像素会有4个数据(RGBA),RGB是红绿蓝,A指的是透明度。

举个例子:本文720480的水果图片,一共有720 480 = 259200像素,每个像素又有4个数据,所以数据数组的总长度为259200 * 4 = 1036800。

可以看到图片的数据很长,如果一次性处理很多图片的时候,计算量相当可观,所以例子中会使用worker,把繁重的计算任务交给后台线程。

算法的基本步骤

  1. 取得每一个像素的red,green,blue值。

  2. 使用灰度算法,算出一个灰度值。

  3. 用这个灰度值代替像素原始的red,green,blue值。

比如我们的灰度算法是:

Gray = (Red + Green + Blue) / 3

计算过程:

//伪代码
for(var Pixel in Image){var Red = Image[Pixel].Redvar Green = Image[Pixel].Greenvar Blue = Image[Pixel].Bluevar Gray = (Red + Green + Blue) / 3Image[Pixel].Red = GrayImage[Pixel].Green = GrayImage[Pixel].Blue = Gray
}

很简单对吧。

很多好吃的鲜艳水果,但是它们马上要变灰了!!

算法1 - 平均法

使用算法1:

这是最常见的灰度算法,简单暴力,把它放到第一位。公式是:

 Gray = (Red + Green + Blue) / 3

这个算法可以生成不错灰度值,因为公式简单,所以易于维护和优化。然而它也不是没有缺点,因为简单快速,从人眼的感知角度看,图片的灰度阴影和亮度方面做的还不够好。所以,我们需要更复杂的运算。

算法2 - 基于人眼感知

使用算法2:

算法1与算法2生成的图片似乎没太大差别,所以增加一个例子,将图片上半部分用算法1,下半部分用算法2。

上半部分是算法1,下半部分是算法2:

仔细看的话,中间有一根黑线。上半部分(算法1)比下半部分(算法2)更苍白一些。如果还是看不出来,注意最右边的柠檬,算法1的柠檬反光更强烈,算法2的柠檬更柔和。

第二种算法考虑到了人眼对不同光感知程度不同。人的眼睛内有几种辨别颜色的锥形感光细胞,分别对黄绿色、绿色和蓝紫色的光最敏感。虽然眼球中的椎状细胞并非对红、绿、蓝三色的感受度最强,但是由肉眼的椎状细胞所能感受的光的带宽很大,红、绿、蓝也能够独立刺激这三种颜色的受光体。

人类对红绿蓝三色的感知程度依次是: 绿>红>蓝,所以平均算法从这个角度看是不科学的。应该按照人类对光的感知程度为每个颜色设定一个权重,它们的之间的地位不应该是平等的。

一个图像处理通用的公式是:

Gray = (Red * 0.3 + Green * 0.59 + Blue * 0.11)

可以看到,每个颜色的系数相差很大。

现在对图像灰度处理的最佳公式还存在争议,有一些类似的公式:

Gray = (Red * 0.2126 + Green * 0.7152 + Blue * 0.0722)

or

Gray = (Red * 0.299 + Green * 0.587 + Blue * 0.114)

它们只是在系数上存在一些偏差,大体的比值差不多。

算法3 - 去饱和

使用算法3:

在说这个算法之前,先说说RGB,大多数程序员都使用RGB模型,每一种颜色都可以由红绿蓝组成,RGB对计算机来说可以很好的描述颜色,但对于人类而言就很难理解了。如果升国旗的时候说,“五星红旗多么RGB(255, 0, 42)”,可能会被暴打一顿。但我说鲜红的五星红旗,老师可能会点头称赞。

所以为了更通俗易懂,有时我们选择HLS模型描述颜色,这三个字母分别表示Hue(色调)、Saturation(饱和度)、Lightness(亮度)。色调,取值为:0 - 360,0(或360)表示红色,120表示绿色,240表示蓝色,也可取其他数值来指定颜色。饱和度,取值为:0.0% - 100.0%,它通常指颜色的鲜艳程度。亮度,取值为:0.0% - 100.0%,黑色的亮度为0。

去饱和的过程就是把RGB转换为HLS,然后将饱和度设为0。因此,我们需要取一种颜色,转换它为最不饱和的值。这个数学公式比本文介绍的更复杂,这里提供一个简单的公式,一个像素可以被去饱和通过计算RGB中的最大值和最小值的中间值:

Gray = ( Math.max(Red, Green, Blue) + Math.min(Red, Green, Blue) ) / 2

去饱和后,图片立体感减弱,但是更柔和。对比算法2,可以很明显的看出差异,从效果上看,可能大多数人都喜欢算法2,算法3是目前为止,处理的图片立体感最弱,最黑暗的。

算法4 - 分解

取最大值

取最小值

分解算法可以认为是去饱和更简单一种的方式。分解是基于每一个像素的,只取RGB的最大值或者最小值。

最大值分解:

Gray = Math.max(Red, Green, Blue)

最小值分解:

Gray = Math.min(Red, Green, Blue)

正如上面展现的,最大值分解提供了更明亮的图,而最小值分解提供了更黑暗的图。

算法5 - 单一通道

取红色通道

取绿色通道

取蓝色通道

图片变灰更快捷的方法,这个方法不用做任何计算,取一个通道的值直接作为灰度值。

Gray = Red

or

Gray = Green

or

Gray = Blue

不管相不相信,大多数数码相机都用这个算法生成灰度图片。很难预测这种转换的结果,所以这种算法多用于艺术效果。

算法6 - 自定义灰度阴影

NumberOfShades = 4

这是到目前为止最有趣的算法,允许用户提供一个灰色阴影值,值的范围在2-256。2的结果是一张全白的图片,256的结果和算法1一样。

NumberOfShades = 16

该算法通过选择阴影值来工作,它的公式有点复杂

ConversionFactor = 255 / (NumberOfShades - 1)
AverageValue = (Red + Green + Blue) / 3
Gray = Math.round((AverageValue / ConversionFactor) + 0.5) * ConversionFactor
  • NumberOfShades 的范围在2-256。

  • 从技术上说,任何灰度算法都可以计算AverageValue,它仅仅提供一个初始灰度的估计值。

  • “+ 0.5” 是一个可选参数,用于模拟四舍五入。

小节

这是一篇很有趣的文章,不仅仅是介绍灰度算法,对了解图片的处理过程也很有帮助。

References

  • Seven grayscale conversion algorithms (with pseudocode and VB6 source code)

有趣的6种图片灰度转换算法相关推荐

  1. MATLAB | sRGB图像的灰度转换算法

    列举了几种常见的灰度转换算法,通过计算结构相似性参数评价不同转换方式所得到灰度图片之间的相似性,并绘制了不同灰度图片之间的差异. % gray_convert.m % sRGB图像转换为灰阶图 Rr ...

  2. 如何将JPG转换为PNG?两种图片格式转换的方法交给你

    在平时的工作生活当中,大家都会使用到各种各样的图片,其中jpg格式与png格式都是大家平时比较常用的图片格式,但是在使用图片时,可能会遇到只能上传其中某种格式的情况,那么这时候就需要将图片转换成相应的 ...

  3. php比例算法,图片比例转换算法

    项目要求将图片上传的任意图片按固定比例进行转换,没办法自己就写了一个,代码如下: public function cropImage($imagePath, $savePath, $scale){ $ ...

  4. python3 PIL、opencv, 二进制、base64 四种图片格式转换

    https://blog.csdn.net/cnmnui/article/details/105831908

  5. 人脸识别基础-灰度转换与修改图片尺寸

    目录 一.灰度转换 1.定义: 2.作用 二.灰度处理代码 三.图片调整大小 一.灰度转换 1.定义: 灰度变换也被称为图像的点运算(只针对图像的某一像素点)是所有图像处理技术中最简单的技术,其变换形 ...

  6. 3个无敌实用的图片转换器,上百种图片格式任意转

    分享3个万能的图片格式转换工具,每个基本上都提供了上百种图片格式转换,而且压缩后的图片一点都不会损坏原画质,压缩完成后还能自动下载保存到相册,转换速度不仅快而且还提供了其他的图片处理功能. 1.万能图 ...

  7. 电子稳像技术-灰度投影算法

    背景介绍 汽车的随机振动具有以下特点: 1.振动没有固定的周期,无法预测某一时刻t的振幅,速度和加速度 2.在相同条件下进行测试,各次记录的结果不可能完全一致 3.汽车高频振动对摄像机成像产生帧内模糊 ...

  8. 论文、报告及教案公式编辑:图片公式转换Mathpix snipping Tool、快速编辑神器AxMath插件操作使用的几种用法(最详细精致)

    图片公式转换Mathpix snipping Tool及快速编辑神器AxMath插件操作使用的几种用法(最详细精致) [文章内容较多, 点击目录链接可直达标题内容] 文章目录 图片公式转换Mathpi ...

  9. 【上】带你玩转人脸识别--读取图片,灰度转换,尺寸修改,绘制矩形快速入门

    文章目录 前 言 安 装 OpenCV 导入模块 1.读取图片 (imread,imshow) 2.灰度转换 (cvtColor) 3.尺寸修改 (resize) 4.矩形.圆形的绘制 (rectan ...

最新文章

  1. JAVA获取局域网内对应IP电脑的MAC地址(物理地址)
  2. centos6.4 yum装php,CentOS6.x/6.5/6.4/6.3/6.2/7.x 64位安装php5.2(使用YUM自动安装)
  3. ZYNQ 的三种GPIO :MIO EMIO AXI_GPIO
  4. 页面缩放android浏览器,适用于所有移动浏览器的完整网页和禁用的缩放视口元标记...
  5. Policy-based RL小结(Policy Gradient ; Natural policy gradient ;TRPO;ACKTR;PPO )
  6. 浅谈StringBuilder
  7. PostgreSQL安装和简单配置
  8. java配置运行环境和配置
  9. 拿过3个重点、8个面上的专家:申请国家基金心得与体会
  10. C1见习工程师(一)
  11. 编写c高级语言程序步骤,高级语言程序设计知识点总结一
  12. [工具:iperf吞吐率测试工具 ]安装以及使用
  13. 集成测试(自顶向下,自底向上,三明治)
  14. 给出问题的答案 你就可以成为百万富翁
  15. 苹果27寸一体机拆机图解_苹果新iMac一体电脑拆机图解
  16. ZigBee模块无线传输星形拓扑组网结构简介
  17. 绕过AppLocker系列之MSIEXEC的利用
  18. 【小程序】自定义导航栏
  19. 在Linux下驱动D-link DFE-530TX(最终稿)(转)
  20. 偏财入财库大富_偏财入库无人不富是什么意思

热门文章

  1. Drawable之color示例
  2. 再谈编程范式—程序语言背后的思想
  3. MongoDB Hot Backup 测试及痛点
  4. nth-of-type和nth-child
  5. [Android] 环境优化配置Android Studio发展NDK
  6. [每天一个知识点]31-乱七八糟-如何判断预言有效
  7. 典型重构3 (Try/Catch)
  8. 创建简单的maven archetype
  9. MooTools 1.4 源码分析 - (关于Core、Type等模块分析)
  10. C#中的String类