问题描述
基本上我想为我的绘画应用程序实现颜色替换功能。
以下是原始和预期产出
原文:
更改用户选择的墙面颜色以及更换的某个阈值
我尝试了两种方法,但无法按预期工作
方法1:
但是我无法理解逻辑并且不确定我在第3步的代码实现。
请按照我的理解找到以下代码。
1)使用cvCvtColor将图像从RGB转换为HSV(我们只希望
更改色调)。
IplImage * mainImage = [self CreateIplImageFromUIImage:[UIImage imageNamed:@original.jpg]];
IplImage * hsvImage = cvCreateImage(cvGetSize(mainImage),IPL_DEPTH_8U,3);
IplImage * threshImage = cvCreateImage(cvGetSize(mainImage),IPL_DEPTH_8U,3);
cvCvtColor(mainImage,hsvImage,CV_RGB2HSV);
2)用cvThreshold隔离颜色,指定
一定的容差(你想要的范围是颜色,而不是一个平面颜色)。
cvThreshold(hsvImage,threshImage,0,100,CV_THRESH_BINARY);
3)使用blob检测
库(如cvBlobsLib)丢弃低于最小尺寸的颜色区域。这将消除场景中类似
颜色的点。 我是否需要指定原始图像或thresold图像?
CBlobResult blobs = CBlobResult(threshImage,NULL ,0);
blobs.Filter(blobs,B_EXCLUDE,CBlobGetArea(),B_LESS,10);
4)使用cvInRangeS掩盖颜色并使用
结果掩码应用新色调。
不确定此函数如何帮助进行颜色替换,并且无法理解要提供的参数。
5)cv使用
新色调对新图像进行处理,图像由第一步中保存的饱和度和亮度
通道组成。
据我所知,cvMerge将合并HS和V的三个通道,但我如何使用上述三个步骤的输出。
所以基本上坚持使用opencv实现,
如果可能的话请指导我进行opencv实现或任何其他解决方案尝试。
最后,我可以使用以下javacv代码实现一些所需的输出,同样也可以移植到opencv。
此解决方案有2个问题
- 没有边缘检测,我认为使用轮廓我可以实现它
-
替换颜色有平坦的色调和坐姿应根据源设置
像素色调坐差但不知道如何实现。可能是
而不是cvSet使用cvAddSIplImage image = cvLoadImage(sample.png);
CvSize cvSize = cvGetSize(image);
IplImage hsvImage = cvCreateImage(cvSize,image.depth(),image.nChannels());
IplImage hChannel = cvCreateImage(cvSize,image.depth(),1);
IplImage sChannel = cvCreateImage(cvSize,image.depth(),1);
IplImage vChannel = cvCreateImage(cvSize,image.depth(),1);
cvSplit(hsvImage,hChannel,sChannel,vChannel,null);
IplImage cvInRange = cvCreateImage(cvSize,image.depth(),1);
CvScalar source = new CvScalar(72 / 2,0.07 * 255,66,0); //源颜色替换
CvScalar from = getScaler(source,false);
CvScalar to = getScaler(source,true);
cvInRangeS(hsvImage,from,to,cvInRange);
IplImage dest = cvCreateImage(cvSize,image.depth(),image.nChannels());
IplImage temp = cvCreateImage(cvSize,IPL_DEPTH_8U,2);
cvMerge(hChannel,sChannel,null,null,temp);
cvSet(temp,new CvScalar(45,255,0,0),cvInRange); //目标色调和sat
cvSplit(temp,hChannel,sChannel,null,null);
cvMerge(hChannel,sChannel,vChannel,null,dest);
cvCvtColor(dest,dest,CV_HSV2BGR);
cvSaveImage(output.png,dest);
计算门槛的方法
CvScalar getScaler(CvScalar seed,boolean plus){
if(plus){
return CV_RGB(seed.red( )+(seed.red()* thresold),seed.green()+(seed.green()* thresold),seed.blue()+(seed.blue()* thresold));
} else {
返回CV_RGB(seed.red() - (seed.red()* thresold),seed.green() - (seed.green()* thresold),seed.blue( ) - (seed.blue()* thresold));
}
}
Basically i want to implement color replacement feature for my paint application.Below are original and expected output
Original:
After changing wall color selected by user along with some threshold for replacement
I have tried two approaches but could not got working as expected
Approach 1:
Queue-based Flood Fill algorithm for color replacementbut with i got below output with terribly slow and wall shadow has not been preserved.
Approach 2:So i have tried to look at another option and found below post from SOHow to change a particular color in an image?
but i could not understand logic and not sure about my code implementation from step 3.
Please find below code for each step wise with my understanding.
1) Convert the image from RGB to HSV using cvCvtColor (we only want to change the hue).
IplImage *mainImage=[self CreateIplImageFromUIImage:[UIImage imageNamed:@"original.jpg"]];
IplImage *hsvImage = cvCreateImage(cvGetSize(mainImage), IPL_DEPTH_8U, 3);
IplImage *threshImage = cvCreateImage(cvGetSize(mainImage), IPL_DEPTH_8U, 3);
cvCvtColor(mainImage,hsvImage,CV_RGB2HSV);
2) Isolate a color with cvThreshold specifying a certain tolerance (you want a range of colors, not one flat color).
cvThreshold(hsvImage, threshImage, 0, 100, CV_THRESH_BINARY);
3) Discard areas of color below a minimum size using a blob detection library like cvBlobsLib. This will get rid of dots of the similar color in the scene. Do i need to specify original image or thresold image?
CBlobResult blobs = CBlobResult(threshImage, NULL, 0);
blobs.Filter( blobs, B_EXCLUDE, CBlobGetArea(), B_LESS, 10);
4) Mask the color with cvInRangeS and use the resulting mask to apply the new hue.
Not sure about this function how it helps in color replacement and not able to understand arguments to be provided.
5) cvMerge the new image with the new hue with an image composed by the saturation and brightness channels that you saved in step one.
i understand that cvMerge will merge three channel of H S and V but how i can use output of above three steps.
so basically stuck with opencv implementation,
if possible then please guide me for opencv implemenation or any other solution to tryout.
Finally i am able to achieve some desired output using below javacv code and same ported to opencv too.
this solution has 2 problems
- don't have edge detection, i think using contours i can achieve it
replaced color has flat hue and sat which should set based on sourcepixel hue sat difference but not sure how to achieve that. may beinstead of cvSet using cvAddS
IplImage image = cvLoadImage("sample.png"); CvSize cvSize = cvGetSize(image); IplImage hsvImage = cvCreateImage(cvSize, image.depth(),image.nChannels()); IplImage hChannel = cvCreateImage(cvSize, image.depth(), 1); IplImage sChannel = cvCreateImage(cvSize, image.depth(), 1); IplImage vChannel = cvCreateImage(cvSize, image.depth(), 1); cvSplit(hsvImage, hChannel, sChannel, vChannel, null); IplImage cvInRange = cvCreateImage(cvSize, image.depth(), 1); CvScalar source=new CvScalar(72/2,0.07*255,66,0); //source color to replace CvScalar from=getScaler(source,false); CvScalar to=getScaler(source, true); cvInRangeS(hsvImage, from , to, cvInRange); IplImage dest = cvCreateImage(cvSize, image.depth(), image.nChannels()); IplImage temp = cvCreateImage(cvSize, IPL_DEPTH_8U, 2); cvMerge(hChannel, sChannel, null, null, temp); cvSet(temp, new CvScalar(45,255,0,0), cvInRange);// destination hue and sat cvSplit(temp, hChannel, sChannel, null, null); cvMerge(hChannel, sChannel, vChannel, null, dest); cvCvtColor(dest, dest, CV_HSV2BGR); cvSaveImage("output.png", dest);
method to for calculating threshold
CvScalar getScaler(CvScalar seed,boolean plus){
if(plus){
return CV_RGB(seed.red()+(seed.red()*thresold),seed.green()+(seed.green()*thresold),seed.blue()+(seed.blue()*thresold));
}else{
return CV_RGB(seed.red()-(seed.red()*thresold),seed.green()-(seed.green()*thresold),seed.blue()-(seed.blue()*thresold));
}
}
这篇关于用于iphone应用的图像颜色替换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!