OpenCVで、画像の特定領域のHSV(HSB)を増やしたり減らしたりするツール「colortrans」を作った。
コマンドラインからファイル名を渡すと実行できるタイプ。

こんなコマンドでお手軽一発生成できます

colortrans ../data/shokai.jpg result.jpg -30 50 -10 ../data/shokai-mask.bmp


できた画像
face color transition


■ダウンロード
mercurialリポジトリをbitbucketに置いた。
shokai / twitter face color change / overview — bitbucket.org
Ubuntu8.04でビルドしたバイナリもコミットしておいた。OpenCVなので他環境でも同じコードをコンパイルしなおせば実行できるはず。


twitterでriywoさんがアイコンに自分の最近の発言ワードを出しているのを見て、じゃあ自分の顔色を使って何か表現できないかという事で作り始めた。なのでリポジトリ名が twitter face color change になっている
でもまだ何と色を連動させればいいのか決めかねているので、アップローダはまだ書いてない。たぶんtwitterと関係のないリアルワールドの情報の方が面白い。俺の脈拍とかクリエイティブビートとか・・・




■顔だけ色を変える方法
画像認識ではできそうにないので、手動でマスクを作る

イラレでもPhotoshopでもいい。
making mask


元画像と同じサイズで、顔部分だけ黒で描く画像間違えた。顔を白で、顔以外を黒で描くだった
making mask


モノクロ2階調のBMP形式で保存する
making mask
ファイル名はなんでもいい。



できたマスクBMP画像と、今回使うjpeg元画像



■変換する
colortransというUbuntuでビルドしたバイナリがコミットしてあるので、

入力ファイル名 出力ファイル名 Hue Saturation Value マスクファイル名

の順に引数を渡すとできる。

colortrans shokai.jpg result.jpg -30 50 -10 mask.bmp



マスクを指定しないと、画像全体の色を遷移させる事も出来る

colortrans shokai.jpg result.jpg 40 0 0

face color transition
これはこれで何かに使えるかもしれない



■プログラム
MacやWindowsでも、OpenCVをはじめたで書いたとおりビルド環境を作れば使える。
OpenCVは簡単なので、各言語バインディング使うより普通にCで書いた方がいいと思う

colortrans.cpp

#include <stdio.h>
#include <highgui.h>
#include <cv.h>

IplImage *img = NULL;
IplImage *imgMask = NULL;
IplImage *imgHsv, *imgResult, *imgHue, *imgSat, *imgVal;

int main(int argc, char** argv){
  if(argc < 6){
    puts("Put filenames and HSV(HSB) as ARGS");
    puts(" colorchange input output H(int) S(int) V(int) (mask)");
    puts("Usage:");
    puts(" colortrans ../data/shokai.jpg result.jpg -30 50 -10 ../data/shokai-mask.jpg");
    puts(" colortrans ../data/shokai.jpg result.jpg 40 0 0");
    return -1;
  }

  img = cvLoadImage(argv[1], CV_LOAD_IMAGE_COLOR);
  if(argc > 6) imgMask = cvLoadImage(argv[6], CV_LOAD_IMAGE_GRAYSCALE);

  imgHsv = cvCreateImage(cvSize(img->width, img->height), IPL_DEPTH_8U, 3);
  imgResult = cvCreateImage(cvSize(img->width,img->height), IPL_DEPTH_8U, 3);
  imgHue = cvCreateImage(cvSize(img->width,img->height), IPL_DEPTH_8U, 1);
  imgSat = cvCreateImage(cvSize(img->width,img->height), IPL_DEPTH_8U, 1);
  imgVal = cvCreateImage(cvSize(img->width,img->height), IPL_DEPTH_8U, 1);

  cvCvtColor(img, imgHsv, CV_BGR2HSV);
  cvSplit(imgHsv, imgHue, imgSat, imgVal, NULL);
  cvAddS(imgHue, cvScalarAll(atoi(argv[3])), imgHue, imgMask);
  cvAddS(imgSat, cvScalarAll(atoi(argv[4])), imgSat, imgMask);
  cvAddS(imgVal, cvScalarAll(atoi(argv[5])), imgVal, imgMask);
  cvMerge(imgHue, imgSat, imgVal, NULL, imgHsv);
  cvCvtColor(imgHsv, imgResult, CV_HSV2BGR);

  cvSaveImage(argv[2], imgResult);
}