基本上我想为我的绘画应用程序实现颜色替换功能。 以下是原始和预期的输出
原件:
更改用户选择的墙面颜色以及更换的某个阈值
我尝试了两种方法,但无法按预期工作
方法1:
用于颜色替换的Queue-based Flood Fill算法
但是我得到了低于输出的速度非常缓慢,并且没有保留墙影。
方法2: 所以我试着看看另一个选项,发现在SO的帖子下面 How to change a particular color in an image?
但是我无法理解逻辑并且不确定我在第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)使用指定a的cvThreshold隔离颜色 一定的公差(你想要一系列颜色,而不是一种颜色)。
cvThreshold(hsvImage, threshImage, 0, 100, CV_THRESH_BINARY);
3)使用斑点检测丢弃低于最小尺寸的颜色区域 像cvBlobsLib这样的库。这将摆脱类似的点 场景中的颜色。 我是否需要指定原始图像或背景图像?
CBlobResult blobs = CBlobResult(threshImage, NULL, 0);
blobs.Filter( blobs, B_EXCLUDE, CBlobGetArea(), B_LESS, 10);
4)用cvInRangeS掩盖颜色并使用 结果蒙版应用新的色调。
不确定此函数如何帮助进行颜色替换,并且无法理解要提供的参数。
5)cvMerge新图像用 具有由饱和度和亮度组成的图像的新色调 您在第一步中保存的频道。
据我所知,cvMerge将合并H S和V的三个通道,但我如何使用上述三个步骤的输出。
所以基本上坚持使用opencv实现,
如果可能的话请指导我进行opencv实现或任何其他尝试的解决方案。
答案 0 :(得分:4)
最后,我可以使用下面的javacv代码实现一些所需的输出,同样也可以移植到opencv。
此解决方案有2个问题
替换颜色具有平坦的色调和坐姿,应根据来源设置 像素色调差异但不确定如何实现。也许 而不是使用cvAddS
的cvSetIplImage 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);
计算阈值的方法
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));
}
}
答案 1 :(得分:0)
我知道这个答案总有一天对某人有用。 在您的iOS视图viewdidLoad()覆盖方法中尝试一下。 以下代码段中的图像应来自UIImageView 种子也是固定的。您可以根据用户的点击事件将其动态化。
cv::Mat mask = cv::Mat::zeros(image.rows + 2, image.cols + 2, CV_8U);
imageView.image = [self UIImageFromCVMat:image];
cv::cvtColor(image, image, cv::COLOR_BGR2RGB);
try {
if(seed.x > 0 && seed.y > 0){
cv::floodFill(image, mask, seed, cv::Scalar(50, 155, 20) ,0, cv::Scalar(2,2, 2), cv::Scalar(2,2, 2), 8);
cv::floodFill(image, mask, seed2, cv::Scalar(50, 155, 20) ,0, cv::Scalar(2,2, 2), cv::Scalar(2,2, 2), 8);
cv::floodFill(image, mask, seed3, cv::Scalar(50, 155, 0) ,0, cv::Scalar(2,2, 2), cv::Scalar(2,2, 2), 8);
}
} catch (Exception ex) {
}
cv::cvtColor(image, image, cv::COLOR_RGB2BGR);
self.imageView.contentMode = UIViewContentModeScaleAspectFill;
self.imageView.image = [self UIImageFromCVMat:image];