隐藏图不是什么新鲜的东西,具体表现在大部分社交软件中,预览图看到的是一张图,而点开后看到的又是另一张图。虽然很早就看到过这类图片,但是一直没有仔细研究过它的原理,今天思考了一下,发现挺有趣的,所以自己也写了个简单的算法把两张图片合成为一张隐藏图。

比如下面这张图。

当背景颜色为白色时,通常也就是在预览状态下,它是这个样子的

而当背景颜色变黑以后,通常也就是点开图片以后,它是这样子的。。

隐藏图原理

  我们知道一张图片中具有透明度的像素会叠加一部分的背景色,因此当背景色为白色时,所有具有透明度的白色像素全部显示为纯白色,当背景色为黑色时,所有具有透明度的黑色会显示为纯黑色。因此我们只需要把图片一的所有像素根据其灰度值转换成不同透明度的黑色,将图片二的所有像素根据其灰度值转换成不同透明度的白色,并将两图的所有像素按照任意规律交叉排列,即可生成隐藏图。这样当背景色为黑色时,图一的所有像素将会显示为纯黑色,图二的所有像素会因为其透明度不同显现出不同的灰色,此时图一隐藏,图二显现,反之同理。

算法实现

  基本的算法思路上面已经提过了,可以说是一个相当简单的算法了。不过具体有几点需要注意:

  1. 由其原理可知,隐藏图只能是黑白的,不能是彩色的,因此当遇到彩色像素时,需要将其转换成灰度。对于彩色转灰度,心理学中有一个公式:Gray = R*0.299 + G*0.587 + B*0.114,我们需要做的是根据算出来的灰度设定像素透明度。在白色背景下,黑色像素的灰度会随着像透明度增高而降低,在黑色背景下,白色像素的灰度会随着透明度增高而增高
  2. 考虑到需要合成的两张图片尺寸不一致,为了保证生成的隐藏图能够完成保留两张图片信息并且不发生变形,我们需要将最终图片的长和宽设定为两张图片尺寸中最大的长和最大的宽

好的,接下来把我的代码实现贴出来吧

  1. using System;
  2. using System.IO;
  3. using System.Drawing;
  4.  
  5. class MainClass
  6. {
  7. public static void Main(string[] args)
  8. {
  9. //图片一的文件路径
  10. Stream blackImageReader = new FileStream("/Users/shiyidu/Desktop//1.jpg", FileMode.Open);
  11. Bitmap blackImage = new Bitmap(blackImageReader);
  12.  
  13. //图片二的文件路径
  14. Stream whiteImageReader = new FileStream("/Users/shiyidu/Desktop//2.jpg", FileMode.Open);
  15. Bitmap whiteImage = new Bitmap(whiteImageReader);
  16.  
  17. //生成最终图片
  18. Bitmap finalImage = CalculateHiddenImage(blackImage, whiteImage);
  19.  
  20. //最终图片保存路径
  21. Stream imageCreater = new FileStream("/Users/shiyidu/Desktop//final.png", FileMode.Create);
  22. finalImage.Save(imageCreater, System.Drawing.Imaging.ImageFormat.Png);
  23. }
  24.  
  25. private static Bitmap CalculateHiddenImage(Bitmap blackImage, Bitmap whiteImage)
  26. {
  27. int b_width = blackImage.Width;
  28. int b_height = blackImage.Height;
  29. int w_width = whiteImage.Width;
  30. int w_height = whiteImage.Height;
  31.  
  32. //设定最终图片的尺寸
  33. int f_width = Math.Max(b_width, w_width);
  34. int f_height = Math.Max(b_height, w_height);
  35.  
  36. Bitmap result = new Bitmap(f_width, f_height);
  37.  
  38. //黑色图片距离边缘的距离
  39. int b_widthOffset = b_width == f_width ? : (f_width - b_width) / ;
  40. int b_heightOffset = b_height == f_height ? : (f_height - b_height) / ;
  41.  
  42. //白色图片离边缘距离
  43. int w_widthOffset = w_width == f_width ? : (f_width - w_width) / ;
  44. int w_heightOffset = w_height == f_height ? : (f_height - w_height) / ;
  45.  
  46. for (int x = ; x < f_width; x++) {
  47. for (int y = ; y < f_height; y++) {
  48. //上下左右交叉排列黑白像素
  49. bool blackPixel = (x + y) % == ? true : false;
  50.  
  51. int coor_x;
  52. int coor_y;
  53. //决定当前像素位置是否对应图一或图二某像素,如果没有,跳过循环
  54. bool validPixel = true;
  55. if (blackPixel) {
  56. coor_x = x - b_widthOffset;
  57. if (coor_x > b_width - ) validPixel = false;
  58. coor_y = y - b_heightOffset;
  59. if (coor_y > b_height - ) validPixel = false;
  60. } else {
  61. coor_x = x - w_widthOffset;
  62. if (coor_x > w_width - ) validPixel = false;
  63. coor_y = y - w_heightOffset;
  64. if (coor_y > w_height - ) validPixel = false;
  65. }
  66.  
  67. validPixel = validPixel && coor_x >= && coor_y >= ;
  68. if (!validPixel) continue;
  69.  
  70. //根据颜色计算像素灰度,设定透明度
  71. if (blackPixel) {
  72. Color origin = blackImage.GetPixel(coor_x, coor_y);
  73. int gray = (origin.R * + origin.G * + origin.B * ) >> ;
  74. Color finalColor = Color.FromArgb( - gray, Color.Black);
  75. result.SetPixel(x, y, finalColor);
  76. } else {
  77. Color origin = whiteImage.GetPixel(coor_x, coor_y);
  78. int gray = (origin.R * + origin.G * + origin.B * ) >> ;
  79. Color finalColor = Color.FromArgb(gray, Color.White);
  80. result.SetPixel(x, y, finalColor);
  81. }
  82. }
  83. }
  84.  
  85. return result;
  86. }
  87. }

一个简单的QQ隐藏图生成算法的更多相关文章

  1. 一个简单的QQ隐藏图生成算法 通过jQuery和C#分别实现对.NET Core Web Api的访问以及文件上传

    一个简单的QQ隐藏图生成算法   隐藏图不是什么新鲜的东西,具体表现在大部分社交软件中,预览图看到的是一张图,而点开后看到的又是另一张图.虽然很早就看到过这类图片,但是一直没有仔细研究过它的原理,今天 ...

  2. iOS开发UI篇—使用UItableview完成一个简单的QQ好友列表(一)

    iOS开发UI篇—使用UItableview完成一个简单的QQ好友列表(一) 一.项目结构和plist文件 二.实现代码 1.说明: 主控制器直接继承UITableViewController // ...

  3. 用CAShapeLayer实现一个简单的饼状图(PieView)

    自己写了一个简单的PieView,demo在这里:https://github.com/Phelthas/LXMPieView 效果如图: 参考了https://github.com/kevinzho ...

  4. OS开发UI篇—使用UItableview完成一个简单的QQ好友列表

    本文转自:http://www.cnblogs.com/wendingding/p/3763330.html 一.项目结构和plist文件 二.实现代码 1.说明: 主控制器直接继承UITableVi ...

  5. iOS开发UI篇—使用UItableview完成一个简单的QQ好友列表(二)

    一.实现效果             二.实现代码 1.数据模型部分 YYQQGroupModel.h文件 // // YYQQGroupModel.h // 02-QQ好友列表(基本数据的加载) / ...

  6. java模拟一个简单的QQ

    v 项目源码 https://github.com/hjzgg/java_QQ v 标题效果       package testFour; import java.awt.Color; import ...

  7. php随机数怎么获取?一个简单的函数就能生成

    小美女建了一个站,有些页面相似度比较高,想添加一些字段来实现差异化,比如用php随机数生成从10到100之间随机一个数字.其实会php的朋友几十个字符就能实现了,如下代码所示,简单吧?10代表最小值, ...

  8. 原生js实现一个简单的轮播图

    想锻炼一下自己的原生js能力可以从写一个轮播图开始,轮播图的运用想必大家都知道吧,好了废话不多说,开始记笔记了,一些需要注意的点,我都在代码中标注了 首先是构造html: <div id=&qu ...

  9. 第四十四篇--做一个简单的QQ登录界面

    功能:输入用户名和密码,正确,显示登录成功,为空的话,提示用户名和密码不能为空,还有记住密码功能. MainActivity.java package com.aimee.android.play.q ...

随机推荐

  1. DAO层注入HibernateTemplate的两种方式

    -------------------------siwuxie095                                         DAO 层注入 HibernateTemplat ...

  2. fusioncharts Y轴不显示中文的解决方法(转载)

    使用fusionChart主要是被其界面吸引了,各类图表都很好看,下载以后文档也很周全,支持的语言也很多种 ,容易上手.fusionChart工作原理主要是通过后台传xml数据源给报表前台flash ...

  3. Java动态代理机制详解(类加载,JDK 和CGLIB,Javassist,ASM)

    class文件简介及加载 Java编译器编译好Java文件之后,产生.class 文件在磁盘中.这种class文件是二进制文件,内容是只有JVM虚拟机能够识别的机器码.JVM虚拟机读取字节码文件,取出 ...

  4. 品味性能之道<二>:性能工程师可以具备的专业素养

          性能工程师可以具备的专业素养 程序语言原理,包括:C.C++.java及jvm.ASP,因为建站大部分外围应用和中间件都是JAVA编写,大部分的电商平台采用的ASP编写,底层核心系统是C/ ...

  5. Fully Update And Upgrade Offline Debian-based Systems

    Let us say, you have a system (Windows or Linux) with high-speed Internet connection at work and a D ...

  6. thrift相关资源

    官网资料,具有各语言的例子 https://thrift.apache.org/tutorial/ https://thrift.apache.org/tutorial/py

  7. RocketMQ的客户端连接数调查

    RocketMQ版本:3.4.6 ==问题现象== RocketMQ集群的某个topic,在一部分节点上消费有“断层”,这部分数据一致没办法消费. ==调查过程== 一顿操作猛如虎的调查之后发现, 该 ...

  8. 给自己名字abel.这个好,怎么字母排序都第一

    给自己名字abel.这个好,怎么字母排序都第一

  9. 去掉字符串前后的空格和Tab

    <script language=Javascript>function String.prototype.Trim() {return this.replace(/(^\s*)|(\s* ...

  10. a标签的四个伪类

    A标签的css样式   CSS为一些特殊效果准备了特定的工具,我们称之为“伪类”.其中有几项是我们经常用到的,下面我们就详细介绍一下经常用于定义链接样式的四个伪类,它们分别是: :link    :v ...