前一段时间忙着扩展集群。
其中收获不少,发现了更多自己值得学习的东西。
这里记录一个矩阵运算的高效处理方法。
在opencv的计算机视觉处理中,关于蒙版的处理是很关键的。
比如,针对图像的蒙版处理,被背景的处理。
mask = mask.reshape((img.shape[0], img.shape[1]))
width, height = src_width, src_high
replacement_bg = cv2.resize(replacement_bg_raw, (width, height))
# combine the background and foreground, using the mask and its inverse
inv_mask = 1-mask
img.shape[2]
print("img.shape[2]=" + str(img.shape[2]))
for c in range(img.shape[2]):
img[:,:,c] = img[:,:,c]*mask + replacement_bg[:,:,c]*inv_mask
这段代码实现了一个蒙版和前景图和背景图的合并。
当初这段代码,用C来实现,用了最蠢笨的方法。
//开始按照行生成新图像(算法,img[:,:,c] = img[:,:,c]*mask + replacement_bg[:,:,c]*inv_mask)for (int i = 0; i < curr_frame.rows; i++)
{
for (int j = 0; j < curr_frame.cols; j++)
{
cv::Vec3b& srcColor = curr_frame.at<:vec3b>(i, j);
const cv::Vec3b& backimgColor = back_img_frame.at<:vec3b>(i, j);
srcColor[0] = srcColor[0] * mask.at(i * curr_frame.cols + j) + backimgColor[0] * (1 - mask.at(i * curr_frame.cols + j));
srcColor[1] = srcColor[1] * mask.at(i * curr_frame.cols + j) + backimgColor[1] * (1 - mask.at(i * curr_frame.cols + j));
srcColor[2] = srcColor[2] * mask.at(i * curr_frame.cols + j) + backimgColor[2] * (1 - mask.at(i * curr_frame.cols + j));
}
}
好嘛,一个个像素来,最后虽然得到了我想要的结果。
但是,在640*480的分辨率下,我每帧图像一运算就要30w+次的运算。如果是视频捕获的是720P或者4K的图像,会死人的。
对于矩阵运算,应该有偷巧的方法,想想当年的线性代数已经还给老师了,赶紧重新恶补一下。
网上没有什么特别好的资料,于是自己实现。经过测试,还真让我搞定了。
nc::NdArray<:uint8> mask = nc::frombuffer<:uint8>(mask_array_data.c_str(), mask_array_data.length());
mask = mask.reshape(video_width, video_height);
//开始按照行生成新图像(算法,img[:,:,c] = img[:,:,c]*mask + replacement_bg[:,:,c]*inv_mask)
Mat black_and_write = cv::Mat(mask.numCols(), mask.numRows(), CV_8UC1, (uchar* )mask.data());
Mat black_and_write_3;
Mat output_foreground;
Mat output_background;
black_and_write.convertTo(black_and_write_3, CV_8UC3);
bitwise_and(curr_frame, curr_frame, output_foreground, black_and_write_3);
bitwise_and(back_img_frame, back_img_frame, output_background, 1 - black_and_write_3);
curr_frame = output_foreground + output_background;
实际测试这段代码,转720P的视频都没什么问题。我的CPU直线下降,比python的原生代码测试的速度还要快的多。
看不到循环,内部直接用内存块矩阵与或即可。非常方便。