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

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

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

隐藏图原理
我们知道一张图片中具有透明度的像素会叠加一部分的背景色,因此当背景色为白色时,所有具有透明度的白色像素全部显示为纯白色,而当背景色为黑色时,所有具有透明度的黑色会显示为纯黑色。因此我们只需要把图片一的所有像素根据其灰度值转换成不同透明度的黑色,将图片二的所有像素根据其灰度值转换成不同透明度的白色,并将两图的所有像素按照任意规律交叉排列,即可生成隐藏图。这样当背景色为黑色时,图一的所有像素将会显示为纯黑色,图二的所有像素会因为其透明度不同显现出不同的灰色,此时图一隐藏,图二显现,反之同理。
算法实现
基本的算法思路上面已经提过了,可以说是一个相当简单的算法了。不过具体有几点需要注意:
- 由其原理可知,隐藏图只能是黑白的,不能是彩色的,因此当遇到彩色像素时,需要将其转换成灰度。对于彩色转灰度,心理学中有一个公式:Gray = R*0.299 + G*0.587 + B*0.114,我们需要做的是根据算出来的灰度设定像素透明度。在白色背景下,黑色像素的灰度会随着像透明度增高而降低,在黑色背景下,白色像素的灰度会随着透明度增高而增高。
- 考虑到需要合成的两张图片尺寸不一致,为了保证生成的隐藏图能够完成保留两张图片信息并且不发生变形,我们需要将最终图片的长和宽设定为两张图片尺寸中最大的长和最大的宽。
好的,接下来把我的代码实现贴出来吧
using System;
using System.IO;
using System.Drawing; class MainClass
{
public static void Main(string[] args)
{
//图片一的文件路径
Stream blackImageReader = new FileStream("/Users/shiyidu/Desktop//1.jpg", FileMode.Open);
Bitmap blackImage = new Bitmap(blackImageReader); //图片二的文件路径
Stream whiteImageReader = new FileStream("/Users/shiyidu/Desktop//2.jpg", FileMode.Open);
Bitmap whiteImage = new Bitmap(whiteImageReader); //生成最终图片
Bitmap finalImage = CalculateHiddenImage(blackImage, whiteImage); //最终图片保存路径
Stream imageCreater = new FileStream("/Users/shiyidu/Desktop//final.png", FileMode.Create);
finalImage.Save(imageCreater, System.Drawing.Imaging.ImageFormat.Png);
} private static Bitmap CalculateHiddenImage(Bitmap blackImage, Bitmap whiteImage)
{
int b_width = blackImage.Width;
int b_height = blackImage.Height;
int w_width = whiteImage.Width;
int w_height = whiteImage.Height; //设定最终图片的尺寸
int f_width = Math.Max(b_width, w_width);
int f_height = Math.Max(b_height, w_height); Bitmap result = new Bitmap(f_width, f_height); //黑色图片距离边缘的距离
int b_widthOffset = b_width == f_width ? : (f_width - b_width) / ;
int b_heightOffset = b_height == f_height ? : (f_height - b_height) / ; //白色图片离边缘距离
int w_widthOffset = w_width == f_width ? : (f_width - w_width) / ;
int w_heightOffset = w_height == f_height ? : (f_height - w_height) / ; for (int x = ; x < f_width; x++) {
for (int y = ; y < f_height; y++) {
//上下左右交叉排列黑白像素
bool blackPixel = (x + y) % == ? true : false; int coor_x;
int coor_y;
//决定当前像素位置是否对应图一或图二某像素,如果没有,跳过循环
bool validPixel = true;
if (blackPixel) {
coor_x = x - b_widthOffset;
if (coor_x > b_width - ) validPixel = false;
coor_y = y - b_heightOffset;
if (coor_y > b_height - ) validPixel = false;
} else {
coor_x = x - w_widthOffset;
if (coor_x > w_width - ) validPixel = false;
coor_y = y - w_heightOffset;
if (coor_y > w_height - ) validPixel = false;
} validPixel = validPixel && coor_x >= && coor_y >= ;
if (!validPixel) continue; //根据颜色计算像素灰度,设定透明度
if (blackPixel) {
Color origin = blackImage.GetPixel(coor_x, coor_y);
int gray = (origin.R * + origin.G * + origin.B * ) >> ;
Color finalColor = Color.FromArgb( - gray, Color.Black);
result.SetPixel(x, y, finalColor);
} else {
Color origin = whiteImage.GetPixel(coor_x, coor_y);
int gray = (origin.R * + origin.G * + origin.B * ) >> ;
Color finalColor = Color.FromArgb(gray, Color.White);
result.SetPixel(x, y, finalColor);
}
}
} return result;
}
}
一个简单的QQ隐藏图生成算法的更多相关文章
- 一个简单的QQ隐藏图生成算法 通过jQuery和C#分别实现对.NET Core Web Api的访问以及文件上传
一个简单的QQ隐藏图生成算法 隐藏图不是什么新鲜的东西,具体表现在大部分社交软件中,预览图看到的是一张图,而点开后看到的又是另一张图.虽然很早就看到过这类图片,但是一直没有仔细研究过它的原理,今天 ...
- iOS开发UI篇—使用UItableview完成一个简单的QQ好友列表(一)
iOS开发UI篇—使用UItableview完成一个简单的QQ好友列表(一) 一.项目结构和plist文件 二.实现代码 1.说明: 主控制器直接继承UITableViewController // ...
- 用CAShapeLayer实现一个简单的饼状图(PieView)
自己写了一个简单的PieView,demo在这里:https://github.com/Phelthas/LXMPieView 效果如图: 参考了https://github.com/kevinzho ...
- OS开发UI篇—使用UItableview完成一个简单的QQ好友列表
本文转自:http://www.cnblogs.com/wendingding/p/3763330.html 一.项目结构和plist文件 二.实现代码 1.说明: 主控制器直接继承UITableVi ...
- iOS开发UI篇—使用UItableview完成一个简单的QQ好友列表(二)
一.实现效果 二.实现代码 1.数据模型部分 YYQQGroupModel.h文件 // // YYQQGroupModel.h // 02-QQ好友列表(基本数据的加载) / ...
- java模拟一个简单的QQ
v 项目源码 https://github.com/hjzgg/java_QQ v 标题效果 package testFour; import java.awt.Color; import ...
- php随机数怎么获取?一个简单的函数就能生成
小美女建了一个站,有些页面相似度比较高,想添加一些字段来实现差异化,比如用php随机数生成从10到100之间随机一个数字.其实会php的朋友几十个字符就能实现了,如下代码所示,简单吧?10代表最小值, ...
- 原生js实现一个简单的轮播图
想锻炼一下自己的原生js能力可以从写一个轮播图开始,轮播图的运用想必大家都知道吧,好了废话不多说,开始记笔记了,一些需要注意的点,我都在代码中标注了 首先是构造html: <div id=&qu ...
- 第四十四篇--做一个简单的QQ登录界面
功能:输入用户名和密码,正确,显示登录成功,为空的话,提示用户名和密码不能为空,还有记住密码功能. MainActivity.java package com.aimee.android.play.q ...
随机推荐
- rapidjson使用
Value构造 Value对象最好先声明后初始化,如果声明直接初始化可能出错. rapidjson::Value a; a = val[i]; Value传参 Value传参,最好显式使用右值,如st ...
- Fragment 生命周期 全局变量的声明位置
public class Fragment_shouye extends Fragment { private List<Zixun_shouye> datas; private TopV ...
- struts框架值栈问题七之EL表达式也会获取到值栈中的数据
7. 问题七:为什么EL也能访问值栈中的数据? * StrutsPreparedAndExecuteFilter的doFilter代码中 request = prepare.wrapRequest(r ...
- DB2 SQL1477N问题
ERROR [55019] [IBM][DB2/NT] SQL1477N For table "DB_YHJX.YHJX_FHDKFHZ" an object "521 ...
- postman模拟登录接口
https://blog.csdn.net/qq_22219911/article/details/80235272
- 2013.7.15 非html 标签 ,外层 要用 ‘’
当使用 非 html 标签 是 ,要使用 单引号 作外层 , 双引号 用单层 ,如 <s:if test='direction=="出"'> 可以执行 ,, ...
- eclipse 配置动态web项目在servers中运行
第一步: window->preferences:Server->Runtime Environments窗口,add. 第二步: window->preferences:Proje ...
- C语言基础第三次作业
题目7-1,寻找最小值 1.实验代码: #include<stdio.h> int main() { int i,mark,min,n; scanf("%d", &am ...
- 2018.08.30 NOIP模拟 graph(dfs序/树剖+线段树)
[描述] 给你一个图,一共有 N 个点,2*N-2 条有向边. 边目录按两部分给出 1. 开始的 n-1 条边描述了一颗以 1 号点为根的生成树,即每个点都可以由 1 号点 到达. 2. 接下来的 N ...
- xampp环境 安装 用法 composer
准备工作 1.打开PHP配置文件E:\xampp\php\php.ini确认以下模块已开启(移除前面的分号). extension=php_openssl.dll, extension=php_cur ...