思路:
- 使用PS制作一个png格式的相框。中间为透明的。命名为wraper.png
- 使用openCv读取wraper.png。判定通道4(alpha)是否为0。如果为0则表示透明的部分。如果为255则表示完全不透明的部分。将所有值不为0的像素点在图片中的行、列记录下来。
- 读取要覆盖的图像src.jpg。根据第二步记录的位置坐标,将src.jpg中的图片像素替换成wraper.png的像素值。
注意事项:
- imread()读取图片时,默认读取3个通道,即BGR通道。当读取png图片时,需要制定另一个参数imread(“wraper.png”, -1)。才能读取出4个通道。
- 如果在同一相框下,追求最大的处理速度(例如处理视频流),可以先将wraper的位置信息和非透明的数据信息存储在数组中。这样不需要每一帧都读取比较替换。可以大大提高每一帧的处理速度。
- wraper和srcImg分辨率要相同。如果不同需要自己手动处理。
代码:
Java版本。c++同理:
/**
* 根据读入png格式相框,对其图片进行添加相框
* @author Spade
*
*/
public class Wraper {
private Mat wraper;
private List<int[]> position = new LinkedList<>();
private double[] fillData;
/**
* 创建相框
* @param path 相框的png图片地址。
*/
public Wraper(String path) {
this.wraper = Imgcodecs.imread(path, -1);
if(wraper.empty()) {
System.out.println("读取wraper失败,请检查路径或者格式");
return;
}
// 获取填充位置
for(int i=0; i<wraper.rows(); i++) {
for(int j=0; j<wraper.cols(); j++) {
double [] data = wraper.get(i, j);
if(data[3] != 0) {
int[] pos = {i,j};
position.add(pos);
}
}
}
// 获取填充信息(图框)
if(this.position.size()!=0){
fillData = wraper.get(position.get(0)[0], position.get(0)[1]);
}else {
System.out.print("创建wraper失败");
}
}
/**
* 图片相框添加
* @param src 原图
*/
public void wrap(Mat src) {
// 填充信息
for(int[] it : position) {
src.put(it[0],it[1],fillData[0],fillData[1], fillData[2]);
}
return;
}
public static void main(String[] args) {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
Mat img = Imgcodecs.imread("srcImg.png");
Wraper w = new Wraper("wraper.png");
w.wrap(img);
HighGui.imshow("a", img);
HighGui.waitKey(0);
}
}