http://dl.acm.org/citation.cfm?id=618848
http://www.cs.tau.ac.il/~turkel/imagepapers/ColorTransfer.pdf
この技術を簡単に説明すると、心理を考慮した色空間で、画像Aの色の分布を画像Bの分布に似せると、画像Aの構図で画像Bっぽい画像Cができる、と言ったものです。
画像A |
画像B |
画像C |
でも、Bの哀愁漂う雰囲気は引き継がれていない気がします。こういう微妙な印象は、変えれないのかもしれません。もしかしたら実装が間違っているのかもしれません。よくわかりません。
今日はうどんだな、なんて思ったら、うどんっぽい画像になる、とかそういうこともありません。
うどん |
うどんの雰囲気を持つはずの画像 |
以下、C++コード
#include <iostream> #include <fstream> #include <vector> #include <omp.h> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #if defined(_DEBUG) || defined(DEBUG) #pragma comment(lib, "opencv_core247d.lib") #pragma comment(lib, "opencv_highgui247d.lib") #pragma comment(lib, "opencv_imgproc247d.lib") #else #pragma comment(lib, "opencv_core247.lib") #pragma comment(lib, "opencv_highgui247.lib") #pragma comment(lib, "opencv_imgproc247.lib") #endif void BGR2LSM(cv::Mat bgr, cv::Mat& lsm){ double trans[] = { 0.0402, 0.5783, 0.3811, 0.0782, 0.7244, 0.1967, 0.8444, 0.1288, 0.0241}; lsm = cv::Mat::zeros(bgr.size(),CV_64FC3); for(int i=0;i<bgr.size().height;i++){ for(int j=0;j<bgr.size().width;j++){ for(int k=0;k<3;k++){ double t = 0; for(int l=0;l<3;l++){ if(0==bgr.at<cv::Vec3b>(i,j)[l]){printf("error\n");} t += trans[k*3+l]*(double)bgr.at<cv::Vec3b>(i,j)[l]; } lsm.at<cv::Vec3d>(i,j)[k] = t; } } } } void LSM2BGR(cv::Mat lsm, cv::Mat& bgr){ double trans[] = { 0.0497,-0.2439,1.2045, -1.2186,2.3809,-0.1624, 4.4679,-3.5873,0.1193}; bgr = cv::Mat::zeros(bgr.size(),CV_8UC3); for(int i=0;i<bgr.size().height;i++){ for(int j=0;j<bgr.size().width;j++){ for(int k=0;k<3;k++){ double t = 0; for(int l=0;l<3;l++){ t += trans[k*3+l]*(double)lsm.at<cv::Vec3d>(i,j)[l]; } if(t<0)t=0; if(t>255)t=255; bgr.at<cv::Vec3b>(i,j)[k] = t; } } } } void LSM2logLSM(cv::Mat lsm, cv::Mat& logLSM){ logLSM = cv::Mat::zeros(lsm.size(),CV_64FC3); for(int i=0;i<lsm.size().height;i++){ for(int j=0;j<lsm.size().width;j++){ for(int k=0;k<3;k++){ logLSM.at<cv::Vec3d>(i,j)[k] = log(lsm.at<cv::Vec3d>(i,j)[k]); } } } } void logLSM2LSM(cv::Mat logLSM, cv::Mat& lsm){ lsm = cv::Mat::zeros(logLSM.size(),CV_64FC3); for(int i=0;i<lsm.size().height;i++){ for(int j=0;j<lsm.size().width;j++){ for(int k=0;k<3;k++){ lsm.at<cv::Vec3d>(i,j)[k] = exp(logLSM.at<cv::Vec3d>(i,j)[k]); } } } } void logLSM2LAB_Ruderman(cv::Mat logLSM, cv::Mat& lab){ double trans[] = { 1.0/sqrt(3.0), 1.0/sqrt(3.0), 1.0/sqrt(3.0), 1.0/sqrt(6.0), 1.0/sqrt(6.0),-2.0/sqrt(6.0), 1.0/sqrt(2.0),-1.0/sqrt(2.0), 0 }; lab = cv::Mat::zeros(logLSM.size(),CV_64FC3); for(int i=0;i<logLSM.size().height;i++){ for(int j=0;j<logLSM.size().width;j++){ for(int k=0;k<3;k++){ double t = 0; for(int l=0;l<3;l++){ t += trans[k*3+l]*(double)logLSM.at<cv::Vec3d>(i,j)[l]; } lab.at<cv::Vec3d>(i,j)[k] = t; } } } } void LAB_Ruderman2logLSM(cv::Mat lab, cv::Mat& logLSM){ double trans[] = { sqrt(3.0)/3.0, sqrt(6.0)/6.0, sqrt(2.0)/2.0, sqrt(3.0)/3.0, sqrt(6.0)/6.0,-sqrt(2.0)/2.0, sqrt(3.0)/3.0,-sqrt(6.0)/3.0, 0 }; logLSM = cv::Mat::zeros(lab.size(),CV_64FC3); for(int i=0;i<logLSM.size().height;i++){ for(int j=0;j<logLSM.size().width;j++){ for(int k=0;k<3;k++){ double t = 0; for(int l=0;l<3;l++){ t += trans[k*3+l]*(double)lab.at<cv::Vec3d>(i,j)[l]; } logLSM.at<cv::Vec3d>(i,j)[k] = t; } } } } void BGR2LAB_Ruderman(cv::Mat bgr, cv::Mat &lab){ cv::Mat lsm,logLSM; BGR2LSM(bgr,lsm); LSM2logLSM(lsm,logLSM); logLSM2LAB_Ruderman(logLSM,lab); } void LAB_Ruderman2BGR(cv::Mat lab, cv::Mat& bgr){ cv::Mat lsm,logLSM; LAB_Ruderman2logLSM(lab,logLSM); logLSM2LSM(logLSM,lsm); LSM2BGR(lsm,bgr); } void average(cv::Mat im, cv::Vec3d &mean, cv::Vec3d &var) { for(int k=0;k<3;k++){ mean[k] = 0; } for(int i=0;i<im.size().height;i++){ for(int j=0;j<im.size().width;j++){ for(int k=0;k<3;k++){ mean[k] += im.at<cv::Vec3d>(i,j)[k]; } } } for(int k=0;k<3;k++){ mean[k] /= im.size().height*im.size().width; } for(int i=0;i<im.size().height;i++){ for(int j=0;j<im.size().width;j++){ for(int k=0;k<3;k++){ double t = im.at<cv::Vec3d>(i,j)[k]-mean[k]; var[k] += t*t; } } } for(int k=0;k<3;k++){ var[k] /= im.size().height*im.size().width; } } void correction(cv::Mat& source, cv::Mat target){ cv::Vec3d smean,svar,tmean,tvar; average(source,smean,svar); average(target,tmean,tvar); cv::Vec3d ssd,tsd; for(int k=0;k<3;k++){ ssd[k] = sqrt(svar[k]); tsd[k] = sqrt(tvar[k]); } for(int i=0;i<source.size().height;i++){ for(int j=0;j<source.size().width;j++){ for(int k=0;k<3;k++){ double labd = source.at<cv::Vec3d>(i,j)[k] - smean[k]; source.at<cv::Vec3d>(i,j)[k] = labd*tsd[k]/ssd[k]+tmean[k]; } } } } void normalizeRangeVec3b(cv::Mat &im, int min, int max){ for(int i=0;i<im.size().height;i++){ for(int j=0;j<im.size().width;j++){ for(int k=0;k<3;k++){ im.at<cv::Vec3b>(i,j)[k] = (double)(max-min)*(double)im.at<cv::Vec3b>(i,j)[k]/255.0 + min; } } } } int main(int argc, char* argv[]) { std::string sourcename = "a.jpg"; std::string targetname = "b.jpg"; cv::Mat source = cv::imread(sourcename); cv::Mat target = cv::imread(targetname); normalizeRangeVec3b(source,1,255); normalizeRangeVec3b(target,1,255); //Ruderman cv::Mat sourcelab, targetlab; BGR2LAB_Ruderman(source,sourcelab); BGR2LAB_Ruderman(target,targetlab); correction(sourcelab,targetlab); //reverce LAB_Ruderman2BGR(sourcelab,source); LAB_Ruderman2BGR(targetlab,target); cv::imwrite(targetname+"like"+sourcename,source); return 0; }
No comments:
Post a Comment