你需要的编程练习

高效幻象 通过对自己的行为观察,我发现在很多时候,我以为我掌握了的知识和技能其实并不牢靠。我引以为豪的高效其实犹如一个彩色的肥皂泡,轻轻一碰就会破碎,散落一地。 你可能只是精通搜索 我们现在所处的时代,信息爆炸,每个人每天都会接触,阅读很多的信息,快速消费,快速遗忘。那种每天早上起来如同皇帝批阅奏折的、虚假的误以为掌握知识的错觉,驱动我们进入一个恶性循环。 即使在我们真的打算解决问题,进行主动学习时,更多的也只是在熟练使用搜索引擎而已(在一个领域待久了,你所使用的关键字准确度自然要比新人高一些,仅此而已)。精通了高效率搜索之后,你会产生一种你精通搜索到的知识本身的错觉。 如何写一个Shell脚本 在写博客的时候,我通常会在文章中配图。图片一般会放在一个有固定格式的目录中,比如现在是2016年5月,我本地就会有一个名为$BLOG_HOME/images/2016/05的目录。由于使用的是markdown,在插入图片时我就不得不输入完整的图片路径,如:/images/2016/05/stack-overflow.png。但是我又不太记得路径中的images是单数(image)还是复数(images),而且图片格式又可能是jpg,jpeg,gif或者png,我也经常会搞错,这会导致图片无法正确显示。另外,放入该目录的原始文件尺寸有可能比较大,我通常需要将其缩放成800像素宽(长度无所谓,因为文章总是要从上往下阅读)。 为了自动化这个步骤,我写了一个小的Shell脚本。当你输入一个文件名如:stack-overflow.png后,它会缩放这个文件到800像素宽,结果是一个新的图片文件,命名为stack-overflow-resized.png,另外它将符合markdown语法的文件路径拷贝到剪贴板里:/images/2016/05/stack-overflow-resized.png,这样我在文章正文中只需要用Command+V粘贴就可以了。 有了思路,写起来就很容易了。缩放图片的命令我是知道的: $ convert -resize 800 stack-overflow.png stack-overflow-resized.png 但是要在文件明上加入-resized,需要分割文件名和文件扩展名,在Bash里如何做到这一点呢?Google一下: FULLFILE=$1 FILENAME=$(basename "$FULLFILE") EXTENSION="${FILENAME##*.}" FILENAME="${FILENAME%.*}" convert -resize 800 $FULLFILE $FILENAME-resized.EXTENSION 难看是有点难看,不过还是可以工作的。接下来是按照当前日期生成完整路径,date命令我是知道的,而且我知道它的format格式很复杂,而且跟JavaScript里Date对象的format又不太一样(事实上,世界上有多少种日期工具,基本上就有多少种格式)。再Google一下: $ date +"/images/%Y/%m/" 最后一步将路径拷贝到剪贴板也容易,Mac下的pbcopy我也会用:echo一下字符串变量,再管道到pbcopy即可: PREFIX=`date +"/images/%Y/%m/"` echo "$PREFIX$FILENAME-resized.EXTENSION" | pbcopy 但是将内容粘贴到markdown里之后,我发现这个脚本多了一个换行。我想这个应该是echo自己的行为吧,会给字符串自动加上一个换行符。Google一下,发现加上-n参数就可以解决这个问题。 好了,完整的脚本写好了: #!/bin/bash FULLFILE=$1 FILENAME=$(basename "$FULLFILE") EXTENSION="${FILENAME##*.}" FILENAME="${FILENAME%.*}" convert -resize 800 $FULLFILE $FILENAME-resized.EXTENSION PREFIX=`date +"/images/%Y/%m/"` echo -n "$PREFIX$FILENAME-resized.EXTENSION" | pbcopy 嗯,还不错,整个过程中就用了我十几分钟时间而已,以后我在写博客时插入图片就方便多了! 不过等等,好像有点不对劲儿,我回过头来看了看这段脚本:7行代码只有1行是我独立写的!没有Google的话,查看man date和man echo也可以解决其中一部分问题,不过文件扩展名部分估计又得花较长时间。 仔细分析一下,之前的成就感荡然无存。 更多的例子 我相信,过几周我再来写这样一个简单的脚本时,上面那一幕还是会出现。开发者的IDE的外延已经将Google和Stack Overflow集成了。很难想象没有这两个IDE的插件我要怎样工作。 其实除此之外,日常工作中这样的事情每时每刻都在发生: Ansible里如何创建一个给用户robot读写权限的目录? Python 3中启动简单HTTPServer的命令是? Spring Boot的Gradle String是? Mongodb中如何为用户robot授权? Gulp里一个Task依赖另一个Task怎么写? 等等等等,这个列表可以根据你的技术栈,偏向前端/后端的不同而不同,但是相同的是在Google和Stack Overflow上搜索,阅读会浪费很多时间,而这些本来都是可以避免的。...

May 26, 2016 1 min

ImageMagick - 命令行里的PhotoShop

黑白+单色照片 有很多摄影师通过后期制作出了非常独特的黑白+单色照片,并由此来强调被拍摄主题,绿叶中的红花,紫色花朵的黄色花蕊等;的另一方面,这种照片可以强调背景的灰色,比如雾霾中的交通灯。 比如原图是这样的: 经过处理之后,最终的效果是这样的: 网络上已经有很多的教程来做到这一点,不过都需要使用photoshop来完成颜色的抽取,反色,灰化等。当然,作为程序员,特别是命令行控,自然会想到的是使用图片编辑神器ImageMagick来处理。 基本原理 我们都知道,彩色图片都是由3个通道(红,绿,蓝三个)叠加在一起的(如果图片带有透明通道的话,会有4个通道,我们这里略过)形成的。每个通道都是一张灰度图,并且会根据图片实际的色彩,在不同程度上有明暗差异。 比如上图的花朵,如果我们将jpg本身的RGB分离开,就会得到3张不同的灰度图: 红色通道灰度图: 绿色通道灰度图: 蓝色通道灰度图: 由于原图绿色和紫红色为主要色彩,所以在红色通道中,花朵比较偏向白色,蓝色通道中花朵也会偏向白色,因为紫红色包含红色和蓝色的亮度都比较高,而在绿色通道中,叶子的颜色则更偏向白色一些。 图片的加减 有了灰度图,我们就可以通过不同通道的加减来加强某些色彩,比如蓝色通道和红色通道相减之后,绿色就会被过滤掉,因为绿色在红色和蓝色通道中都表现为灰色: 这时候,我们已经有了花瓣的轮廓,但是还是有些模糊,我们还需要将其二值化。这样做出来的图片被称为mask,这个mask和最终的图片叠加之后,才会将我们关注的部位凸现出来。 实现 ImageMagick提供的命令行工具convert非常强大,我们这里只是用其中很简单的几个: 1. 图片通道的分离 2. 图片相加减 3. 叠加多个图片为一个 要分离一张RGB的图片,只需要指定: $ convert flower.jpg -separate flower_rgb_%d.jpg 这条命令会把图片flower.jpg分离成三张图片,命令中的%d占位符会自动被展开为1,2,3这样的数字,这样这条命令会生成3章图片:flower_rgb_0.jpg,flower_rgb_1.jpg,flower_rgb_2.jpg。 图片的相减也很方便,使用命令: $ convert flower_rgb_2.jpg flower_rgb_0.jpg -compose minus \ -composite flower_minus.jpg 来完成。得到差值文件之后(已经具备了基本轮廓,如果不理想,可以换一个通道试试),就可以进一步二值化了。 命令 $ convert flower_minus.jpg -level 10%,30% flower_mask.jpg 用来生成mask文件,其中10%表示亮度低于10%的点会被认为是黑色,而30%则表示亮度高于30%的点会被认为是白色,这样的出来的图片就是只有黑白两种颜色了。 最后,我们需要将不同的图片合并在一起,形成最终的结果: $ convert flower_rgb_2.jpg flower.jpg flower_mask.jpg -composite flower_final.jpg 注意这里的次序,先是蓝色通道,然后是原图,最后是mask。这样composite的结果就是我们最开始看到的了: 再来看另外一张用同样方式生成的图片:

November 8, 2014 1 min