在 Android 上使用 OpenCV 将一个图像拷贝到另一个图像的中间,可以通过以下步骤实现:
-
加载两个图像:首先需要加载源图像和目标图像。
-
计算位置:计算源图像应放置在目标图像中心的位置。
-
裁剪和拷贝:将源图像复制到目标图像的指定区域中。
实现步骤:
1. 加载图像
首先加载两个图像:一个是目标图像,另一个是源图像。
Mat src = Imgcodecs.imread("path/to/source_image.jpg");
Mat dst = Imgcodecs.imread("path/to/destination_image.jpg");
2. 计算位置
接下来,我们需要计算源图像应放置在目标图像中心的起始位置。假设目标图像较大,源图像较小,我们可以计算出源图像放置的区域。
例如,如果目标图像的大小是 (dst.cols(), dst.rows()),而源图像的大小是 (src.cols(), src.rows()),那么源图像的左上角应该放置在目标图像的中心。
int x = (dst.cols() - src.cols()) / 2;
int y = (dst.rows() - src.rows()) / 2;
这会计算出源图像的左上角应该放置在目标图像中的 (x, y) 坐标。
3. 拷贝图像
通过 Mat 类的 rect 和 copyTo 方法,将源图像的内容复制到目标图像的指定区域。
// 创建目标图像区域
Rect roi = new Rect(x, y, src.cols(), src.rows());
// 获取目标图像的ROI区域
Mat targetROI = dst.submat(roi);
// 将源图像复制到目标图像的ROI区域
src.copyTo(targetROI);
4. 保存或显示结果
拷贝操作完成后,可以选择保存或显示结果。
Imgcodecs.imwrite("path/to/output_image.jpg", dst);
或者在 Android 中使用 ImageView 显示结果,可以将 Mat 转换为 Bitmap 然后显示:
Bitmap bitmap = Bitmap.createBitmap(dst.cols(), dst.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(dst, bitmap);
imageView.setImageBitmap(bitmap);
完整代码示例:
/**
* Bitmap 转Mat
* @param bitmap
* @return
*/
public Mat bitmapToMatWithAlpha(Bitmap bitmap) {
Mat mat = new Mat();
Utils.bitmapToMat(bitmap, mat);
// 确保是 4 通道(BGRA),避免透明通道丢失
if (mat.channels() == 3) {
Imgproc.cvtColor(mat, mat, Imgproc.COLOR_BGR2BGRA);
}
return mat;
}
/**
* 将srcBitmap拷贝到dstBitmap 左上角
* @param srcBitmap
* @param dstBitmap
* @return
*/
public Bitmap overlayImage(Bitmap srcBitmap, Bitmap dstBitmap) {
if (srcBitmap == null || dstBitmap == null) {
Log.e(App.tag, "Source or destination bitmap is null");
return null;
}
// 将 Bitmap 转换为 OpenCV Mat
Mat src =bitmapToMatWithAlpha(srcBitmap);
Mat dst = bitmapToMatWithAlpha(dstBitmap);
// 确保 `src` 和 `dst` 存在
if (src.empty() || dst.empty()) {
Log.e(App.tag, "One of the images could not be converted to Mat");
return null;
}
// 计算 ROI,确保 `src` 没有超出 `dst`
int roiWidth = Math.min(src.cols(), dst.cols());
int roiHeight = Math.min(src.rows(), dst.rows());
// 确保 `roiWidth` 和 `roiHeight` 不为 0
if (roiWidth <= 0 || roiHeight <= 0) {
Log.e(App.tag, "ROI dimensions are invalid");
return null;
}
// 取 `dst` 的左上角 ROI
Rect roi = new Rect(0, 0, roiWidth, roiHeight);
Mat targetROI = dst.submat(roi);
targetROI.setTo(new Scalar(0, 255, 0, 255)); // 绿色填充,看看是否生效
src.copyTo(targetROI);
// 转换回 Bitmap
Bitmap bitmap = Bitmap.createBitmap(dst.width(), dst.height(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(dst, bitmap);
return bitmap;
}
注意事项:
• 图像尺寸:确保源图像不会超出目标图像的范围。如果源图像较大,可能需要先调整源图像的大小。
• 性能:大图像处理时可能会耗费较多的内存和计算资源,特别是在 Android 设备上,可以考虑优化图像尺寸。