我基本上要做的是模糊图像,然后将其与原始图像组合在一起,这样原始图像中的某些区域才会模糊(脸部应该模糊不清)。
我的一般想法是掩盖原始Iwant中的部分模糊,然后将原件模糊为副本并且"合并"他们再次在一起。
在某种程度上,这也有效。
我的图片:
创建这些图像的我的C ++代码:
int main(void) {
cv::Mat srcImage = cv::imread(path);
srcImage.convertTo(srcImage, CV_32FC3, 1.0/255.0);
Mat _mask;
Mat img_gray;
cv::Scalar white = cv::Scalar(255, 255, 255);
cv::Scalar black = cv::Scalar(0, 0, 0);
cv::cvtColor(srcImage, img_gray, cv::COLOR_BGR2GRAY);
img_gray.convertTo(_mask, CV_32FC1);
// face
cv::circle(_mask, cv::Point(430, 350), 200, black, -1, 8, 0);
// eyes
cv::circle(_mask, cv::Point(502, 260), 27, white, -1, 8, 0);
cv::circle(_mask, cv::Point(390, 260), 27, white, -1, 8, 0);
// mouth
cv::ellipse(_mask, cv::Point(440, 390), cv::Point(60, 25), 0, 0, 360, white, -1, 8, 0);
cv::threshold(1.0-_mask, _mask, 0.9, 1.0, cv::THRESH_BINARY_INV);
cv::GaussianBlur(_mask,_mask,Size(21,21),11.0);
cv::Mat res;
cv::Mat bg = Mat(srcImage.size(), CV_32FC3);
bg = cv::Scalar(1.0, 1.0 ,1.0);
vector<Mat> ch_img(3);
vector<Mat> ch_bg(3);
cv::split(srcImage, ch_img);
cv::split(bg, ch_bg);
ch_img[0] = ch_img[0].mul(_mask) + ch_bg[0].mul(1.0 - _mask);
ch_img[1] = ch_img[1].mul(_mask) + ch_bg[1].mul(1.0 - _mask);
ch_img[2] = ch_img[2].mul(_mask) + ch_bg[2].mul(1.0 - _mask);
cv::merge(ch_img, res);
cv::merge(ch_bg, bg);
// original but with white mask
res.convertTo(res, CV_8UC3, 255.0);
imwrite("original_with_mask.jpg", res);
// blur original image
cv::Mat blurredImage;
bilateralFilter(srcImage, blurredImage, 10, 20, 5);
GaussianBlur(srcImage, blurredImage, Size(19, 19), 0, 0);
blurredImage.convertTo(blurredImage, CV_8UC3, 255.0);
imwrite("blurred.jpg", blurredImage);
cv::Mat maskedImage;
maskedImage = Mat(srcImage.size(), CV_32FC3);
// now combine blurred image and original using mask
// this fails
cv::bitwise_and(blurredImage, _mask, maskedImage);
cv::imwrite("masked.jpg", maskedImage);
}
我的问题是cv::bitwise_and(blurredImage, _mask, maskedImage);
失败并带有
OpenCV Error: Sizes of input arguments do not match (The operation is neither 'array op array' (where arrays have the same size and type), nor 'array op scalar', nor 'scalar op array') in binary_op
可能是因为_mask
是单个频道图片,而blurredImage
和maskedImage
是3频道图片。
如何组合我得到的图像,使图像(2)中的当前白色区域使用透明蒙版模糊,使用&#34; soft&#34;边缘?
答案 0 :(得分:5)
您可以使用字节通道值的线性组合,而不是浮点转换。参见
int main(int argc, char* argv[])
{
cv::Mat srcImage = cv::imread("C:/StackOverflow/Input/transparentMaskInput.jpg");
// blur whole image
cv::Mat blurredImage;
//cv::bilateralFilter(srcImage, blurredImage, 10, 20, 5); // use EITHER bilateral OR Gaússian filter
cv::GaussianBlur(srcImage, blurredImage, cv::Size(19, 19), 0, 0);
// create mask
cv::Scalar white = cv::Scalar(255, 255, 255);
cv::Scalar black = cv::Scalar(0, 0, 0);
cv::Mat mask = cv::Mat::zeros(srcImage.size(), CV_8UC1);
// face
cv::circle(mask, cv::Point(430, 350), 200, black, -1, 8, 0);
// eyes
cv::circle(mask, cv::Point(502, 260), 27, white, -1, 8, 0);
cv::circle(mask, cv::Point(390, 260), 27, white, -1, 8, 0);
// mouth
cv::ellipse(mask, cv::Point(440, 390), cv::Point(60, 25), 0, 0, 360, white, -1, 8, 0);
cv::GaussianBlur(mask, mask, cv::Size(21, 21), 11.0);
// byte inversion:
cv::Mat invertedMask = 255 - mask; // instead of inversion you could just draw the "face" black on a white background!
cv::Mat outputImage = cv::Mat(srcImage.size(), srcImage.type());
// for each pixel, merge blurred and original image regarding the blur-mask
for (int y = 0; y < outputImage.rows; ++y)
for (int x = 0; x < outputImage.cols; ++x)
{
cv::Vec3b pixelOrig = srcImage.at<cv::Vec3b>(y, x);
cv::Vec3b pixelBlur = blurredImage.at<cv::Vec3b>(y, x);
float blurVal = invertedMask.at<unsigned char>(y, x)/255.0f; // value between 0 and 1: zero means 100% orig image, one means 100% blurry image
cv::Vec3b pixelOut = blurVal * pixelBlur + (1.0f - blurVal)* pixelOrig;
outputImage.at<cv::Vec3b>(y, x) = pixelOut;
}
cv::imshow("input", srcImage);
cv::imshow("blurred", blurredImage);
cv::imshow("mask", mask);
cv::imshow("inverted mask", invertedMask);
cv::imshow("output", outputImage);
return 0;
}
使用此输入图像:
计算这个模糊和掩码:
通过计算(mask/255) * blur + (1-mask/255)*blur
(线性组合)得到此输出:
答案 1 :(得分:1)
我在OpenCV中为CV_8UC3
的两个CV_8UC1
图像定义了一个函数来做alphaBlend:
//! 2018.01.16 13:54:39 CST
//! 2018.01.16 14:43:26 CST
void alphaBlend(Mat& img1, Mat&img2, Mat& mask, Mat& blended){
// Blend img1 and img2 (of CV_8UC3) with mask (CV_8UC1)
assert(img1.size() == img2.size() && img1.size() == mask.size());
blended = cv::Mat(img1.size(), img1.type());
for (int y = 0; y < blended.rows; ++y){
for (int x = 0; x < blended.cols; ++x){
float alpha = mask.at<unsigned char>(y, x)/255.0f;
blended.at<cv::Vec3b>(y,x) = alpha*img1.at<cv::Vec3b>(y,x) + (1-alpha)*img2.at<cv::Vec3b>(y,x);
}
}
}
然后,很容易对图像进行alpha弯曲,只需调用alphaBlend(...)
即可。这是一个例子:
#include <opencv2/opencv.hpp>
using namespace cv;
//! 2018.01.16 13:54:39 CST
//! 2018.01.16 14:43:26 CST
void alphaBlend(Mat& img1, Mat&img2, Mat& mask, Mat& blended){
// Blend img1 and img2 (of CV_8UC3) with mask (CV_8UC1)
assert(img1.size() == img2.size() && img1.size() == mask.size());
blended = cv::Mat(img1.size(), img1.type());
for (int y = 0; y < blended.rows; ++y){
for (int x = 0; x < blended.cols; ++x){
float alpha = mask.at<unsigned char>(y, x)/255.0f;
blended.at<cv::Vec3b>(y,x) = alpha*img1.at<cv::Vec3b>(y,x) + (1-alpha)*img2.at<cv::Vec3b>(y,x);
}
}
}
Mat createMask(Size sz){
// create mask
cv::Mat mask = cv::Mat::zeros(sz, CV_8UC1);
// white and black
cv::Scalar white = cv::Scalar(255, 255, 255);
cv::Scalar black = cv::Scalar(0, 0, 0);
// face
cv::circle(mask, cv::Point(430, 350), 200, black, -1, 8, 0);
// eyes
cv::circle(mask, cv::Point(502, 260), 27, white, -1, 8, 0);
cv::circle(mask, cv::Point(390, 260), 27, white, -1, 8, 0);
// mouth
cv::ellipse(mask, cv::Point(440, 390), cv::Point(60, 25), 0, 0, 360, white, -1, 8, 0);
// Blur
cv::GaussianBlur(mask, mask, cv::Size(21, 21), 11.0);
return mask;
}
int main(){
cv::Mat img = cv::imread("img04.jpg");
// blur whole image
cv::Mat blured;
//cv::bilateralFilter(img, blured, 10, 20, 5); // use EITHER bilateral OR Gaússian filter
cv::GaussianBlur(img, blured, cv::Size(19, 19), 0, 0);
// Create the mask
Mat mask = createMask(img.size());
Mat mask_inv = 255 - mask;
// Alpha blend
Mat blended1, blended2;
alphaBlend(img, blured, mask, blended1);
alphaBlend(img, blured, mask_inv, blended2);
// Display
cv::imshow("source", img);
cv::imshow("blured", blured);
cv::imshow("mask", mask);
cv::imshow("mask_inv", mask_inv);
cv::imshow("blended1", blended1);
cv::imshow("blended2", blended2);
cv::waitKey();
return 0;
}
来源:
所迷离:
MASK1:
AlphaBlend 1:
面具2:
AlphaBlend 2:
一些有用的链接:
OpenCV C ++中的Alpha混合:Combining 2 images with transparent mask in opencv
OpenCV Python中的Alpha混合: Gradient mask blending in opencv python
答案 2 :(得分:0)
可能是因为_mask是单通道图像和blurImage和 maskedImage是3通道图像。
在调用cv::bitwise_and
:
P.S如果你不想改变你的面具,因为你想在另一个地方使用它,只需在临时变量中进行:
cv::Mat _mask_temp;
cv::cvtColor(_mask,_mask_temp,cv::COLOR_GRAY2BGR);
cv::bitwise_and(blurredImage, _mask_temp, maskedImage);
_mask_temp.release(); // just in case you do not want it anymore to be in your memory(optional)
编辑(另一个问题):
屏幕为32F
,而图片为8U
。所以,你需要这个:
cv::cvtColor(_mask,_mask,cv::COLOR_GRAY2BGR);
_mask.convertTo(_mask, CV_8UC3);