五分钟科普:什么是骰子作画的算法

点击蓝色“五分钟学算法”关注我哟

加个“星标”,一起学算法

640

作者 | 阮一峰

来源 | 阮一峰的博客


今天是周末,给大家分享一个有趣的项目---骰子作画。


程序员 Scott MacDonald 做了一个很有趣的项目----骰子作画。


他用黑底白点的骰子。

640?wx_fmt=png

模拟出一张人像照片。


640?wx_fmt=jpeg


把图像放大,就可以看得更清楚。


640?wx_fmt=jpeg


他一共用了2500多颗骰子。


640?wx_fmt=jpeg


最后的成品就是这样。


640?wx_fmt=jpeg


任何一张图片都可以用骰子模拟出来,算法非常简单:将图片分成若干个区域,每个区域经过计算以后,用1-6之间的一个整数表示,代表骰子的一个面。这种将连续的量转化成不连续的整数的算法,属于vector quantization(矢量量化)的一个应用。


具体来说,


第一步,将图片分割成16像素x16像素的小方块。

 
 
 for (int i=0; i < (pic_width/16); ++i) {    for (int j=0; j < (pic_height/16); ++j) {      patch = cropped_img.get(i*16, j*16, 16, 16);    }  }int i=0; i < (pic_width/16); ++i) {

    for (int j=0; j < (pic_height/16); ++j) {

      patch = cropped_img.get(i*16, j*161616);

    }

  }


第二步,每个小方块内共有256个像素,将每个像素点的灰度值,存入一个数组。

 
 
  for (int k=0; k < patch.pixels.length; ++k) {   x[k] = rgb2gray(patch.pixels[k]);  }  int rgb2gray(int argb) {    int _alpha = (argb >> 24) & 0xFF;    int _red = (argb >> 16) & 0xFF;    int _green = (argb >> 8 ) & 0xFF;    int _blue = (argb) & 0xFF;    return int(0.3*_red + 0.59*_green + 0.11*_blue);  }int k=0; k < patch.pixels.length; ++k) {

   x[k] = rgb2gray(patch.pixels[k]);

  }

  int rgb2gray(int argb) {

    int _alpha = (argb >> 24) & 0xFF;

    int _red = (argb >> 16) & 0xFF;

    int _green = (argb >> 8 ) & 0xFF;

    int _blue = (argb) & 0xFF;

    return int(0.3*_red + 0.59*_green + 0.11*_blue);

  }

第三步,计算该数组的平均值,并用1-6之间的一个整数来表示。

 
 
  int dice_num = six_step_gray(mean(x));  int mean(int[] x) {    float m = 0;    for (int i=0; i < x.length; ++i) {      m += x[i];    }    m = m/x.length;    return int(m);  }  int six_step_gray(int x) {    if (0 <= x && x <= 41) return 1;    if (41 < x && x <= 83) return 2;    if (83 < x && x <= 124) return 3;    if (124 < x && x <= 165) return 4;    if (165 < x && x <= 206) return 5;    if (206 < x && x <= 247) return 6;    else return 6;  }

  int mean(int[] x) {

    float m = 0;

    for (int i=0; i < x.length; ++i) {

      m += x[i];

    }

    m = m/x.length;

    return int(m);

  }

  int six_step_gray(int x) {

    if (0 <= x && x <= 41return 1;

    if (41 < x && x <= 83return 2;

    if (83 < x && x <= 124return 3;

    if (124 < x && x <= 165return 4;

    if (165 < x && x <= 206return 5;

    if (206 < x && x <= 247return 6;

    else return 6;
  }


整数1,表示骰子朝上的一面有1个白点;整数2,表示有2个白点;以此类推。白点越少,表示这个区域越接近全黑;白点越多,表示越接近全白。根据白点值,将骰子依次放入,就能模拟出全图。


这种算法早在1981年就有人提出,当时用的是1~9个白点的多米诺骨牌。


640?wx_fmt=jpeg


如果区域划分得越小,模拟图的生成效果就越好。


640?wx_fmt=jpeg


640?wx_fmt=jpeg


640?wx_fmt=jpeg


640?wx_fmt=jpeg

640?wx_fmt=jpeg


640?wx_fmt=jpeg


此外,不用编程,使用Photoshop也可以得到类似效果。


640?wx_fmt=png


END

640?wx_fmt=png

 原 创 热 文 推 荐 


毕业十年后,我忍不住出了一份程序员的高考试卷

一道腾讯面试题:厉害了我的杯

十大经典排序算法动画与解析,看我就够了

这或许是东半球分析十大排序算法最好的一篇文章

面试官,我会写二分查找法!对,没有 bug 的那种!


640?wx_fmt=png 你点的每个“在看”,我都认真当成了喜欢
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值