关于如何用纯OpenCV实现图片叠加的例子实在是太少,太多的是使用 C++,JNI实现的,如果要用C++的话,我们为啥不转行做C++
下面的例子基于 Android JavaCV 实现了在im_beauty 美女图片上 添加im_flower3 小花图片 并显示
需要在res/drawable目录下 放两个文件 im_beauty, im_flower3 注意im_flower3一定要比im_beauty图片尺寸要下小
package com.KyleOpencvImageAdd; import org.opencv.android.BaseLoaderCallback; import org.opencv.android.LoaderCallbackInterface; import org.opencv.android.OpenCVLoader; import org.opencv.android.Utils; import org.opencv.core.Mat; import org.opencv.core.Rect; import android.os.Bundle; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.BitmapFactory; import android.util.Log; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.ImageView; public class MainActivity extends Activity implements OnClickListener { private Mat mat1,mat2; private ImageView iv1,iv2; //用于显示两张图片叠加 private ImageView iv3; private Button btn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //初始化图片显示 iv1=(ImageView)findViewById(R.id.imageView1); iv1.setImageResource(R.drawable.im_beauty); iv2=(ImageView)findViewById(R.id.imageView2); iv2.setImageResource(R.drawable.im_flower3); iv3=(ImageView)findViewById(R.id.imageView3); btn=(Button)findViewById(R.id.button1); btn.setOnClickListener(this); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) { @Override public void onManagerConnected(int status) { switch (status) { case LoaderCallbackInterface.SUCCESS: { Log.i("", "OpenCV loaded successfully"); } break; default: { super.onManagerConnected(status); } break; } } }; @Override protected void onResume() { // TODO Auto-generated method stub super.onResume(); //初始化函数库 OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_3, this, mLoaderCallback); } @Override public void onClick(View arg0) { // 初始化数据 mat1 = new Mat(); mat2 = new Mat(); Mat mat1Sub = new Mat(); // 加载图片 Bitmap bt1 = BitmapFactory.decodeResource(getResources(), R.drawable.im_beauty); Bitmap bt2 = BitmapFactory.decodeResource(getResources(), R.drawable.im_flower3); Bitmap bt3 = null; // 转换数据 Utils.bitmapToMat(bt1, mat1); Utils.bitmapToMat(bt2, mat2); /** 方法一加权 高级方式 可实现水印效果*********/ // mat1Sub=mat1.submat(0, mat2.rows(), 0, mat2.cols()); // Core.addWeighted(mat1Sub, 1, mat2, 0.3, 0., mat1Sub); /** 方法二 求差 ********/ // submat(y坐标, 图片2的高, x坐标,图片2的宽); // mat1Sub=mat1.submat(0, mat2.rows(), 0, mat2.cols()); // mat2.copyTo(mat1Sub); /*** 方法三兴趣区域裁剪 **/ // 定义感兴趣区域Rect(x坐标,y坐标,图片2的宽,图片2的高) Rect rec = new Rect(0, 0, mat2.cols(), mat2.rows()); // submat(y坐标, 图片2的高, x坐标,图片2的宽); mat1Sub = mat1.submat(rec); mat2.copyTo(mat1Sub); //转化为android识别的图像数据注意bt3的宽高要和mat1一至 bt3 = Bitmap.createBitmap(mat1.cols(), mat1.rows(), Config.RGB_565); Utils.matToBitmap(mat1, bt3); iv3.setImageBitmap(bt3); } }
处理上 bitmap 与mat 的 一定要注意 图片的宽高一致不然容易 Exception
/cv::error()(17079): OpenCV Error: Assertion failed (src.dims == 2 && info.height == (uint32_t)src.rows && info.width ==
(uint32_t)src.cols) in void Java_org_opencv_android_Utils_nMatToBitmap2(JNIEnv*, jclass, jlong, jobject, jboolean), file
/home/reports/ci/slave/50-SDK/opencv/modules/java/generator/src/cpp/utils.cpp, line 97
/org.opencv.android.Utils(17079): nMatToBitmap catched cv::Exception: /home/reports/ci/slave/50-
SDK/opencv/modules/java/generator/src/cpp/utils.cpp:97: error: (-215) src.dims == 2 && info.height == (uint32_t)src.rows &&
info.width == (uint32_t)src.cols in function void Java_org_opencv_android_Utils_nMatToBitmap2(JNIEnv*, jclass, jlong,
jobject, jboolean)