发布时间:2025-06-24 17:45:43  作者:北方职教升学中心  阅读量:917


if (success) { Toast.makeText(this.getApplicationContext(), "OpenCV库加载成功", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(this.getApplicationContext(), "OpenCV库加载失败", Toast.LENGTH_SHORT).show(); }}@Overridepublic boolean onTouch(View view, MotionEvent motionEvent) { int cols = mRgba.cols(); int rows = mRgba.rows(); int xOffset = (mOpenCvCameraView.getWidth() - cols) / 2; int yOffset = (mOpenCvCameraView.getHeight() - rows) / 2; int x = (int)motionEvent.getX() - xOffset; int y = (int)motionEvent.getY() - yOffset; Log.i(TAG, "Touch image coordinates: (" + x + ", " + y + ")"); if ((x < 0) || (y < 0) || (x > cols) || (y > rows)) return false; Rect touchedRect = new Rect(); touchedRect.x = (x>4) ? x-4 : 0; touchedRect.y = (y>4) ? y-4 : 0; touchedRect.width = (x+4 < cols) ? x + 4 - touchedRect.x : cols - touchedRect.x; touchedRect.height = (y+4 < rows) ? y + 4 - touchedRect.y : rows - touchedRect.y; Mat touchedRegionRgba = mRgba.submat(touchedRect); Mat touchedRegionHsv = new Mat(); Imgproc.cvtColor(touchedRegionRgba, touchedRegionHsv, Imgproc.COLOR_RGB2HSV_FULL); // Calculate average color of touched region mBlobColorHsv = Core.sumElems(touchedRegionHsv); int pointCount = touchedRect.width*touchedRect.height; for (int i = 0; i < mBlobColorHsv.val.length; i++) mBlobColorHsv.val[i] /= pointCount; mBlobColorRgba = convertScalarHsv2Rgba(mBlobColorHsv); Log.i(TAG, "Touched rgba color: (" + mBlobColorRgba.val[0] + ", " + mBlobColorRgba.val[1] + ", " + mBlobColorRgba.val[2] + ", " + mBlobColorRgba.val[3] + ")"); mDetector.setHsvColor(mBlobColorHsv); Imgproc.resize(mDetector.getSpectrum(), mSpectrum, SPECTRUM_SIZE, 0, 0, Imgproc.INTER_LINEAR_EXACT); mIsColorSelected = true; touchedRegionRgba.release(); touchedRegionHsv.release(); return false;}private Scalar convertScalarHsv2Rgba(Scalar hsvColor) { Mat pointMatRgba = new Mat(); Mat pointMatHsv = new Mat(1, 1, CvType.CV_8UC3, hsvColor); Imgproc.cvtColor(pointMatHsv, pointMatRgba, Imgproc.COLOR_HSV2RGB_FULL, 4); return new Scalar(pointMatRgba.get(0, 0));}@Overridepublic void onCameraViewStarted(int width, int height) { mRgba = new Mat(height, width, CvType.CV_8UC4); mDetector = new ColorBlobDetector(); mSpectrum = new Mat(); mBlobColorRgba = new Scalar(255); mBlobColorHsv = new Scalar(255); SPECTRUM_SIZE = new Size(200, 64); CONTOUR_COLOR = new Scalar(255,0,0,255);}@Overridepublic void onCameraViewStopped() { mRgba.release();}@Overridepublic Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) { mRgba = inputFrame.rgba(); if (mIsColorSelected) { mDetector.process(mRgba); List<MatOfPoint> contours = mDetector.getContours(); Log.i(TAG, "Contours count: " + contours.size()); Imgproc.drawContours(mRgba, contours, -1, CONTOUR_COLOR); Mat colorLabel = mRgba.submat(4, 68, 4, 68); colorLabel.setTo(mBlobColorRgba); Mat spectrumLabel = mRgba.submat(4, 4 + mSpectrum.rows(), 70, 70 + mSpectrum.cols()); mSpectrum.copyTo(spectrumLabel); } return mRgba;}@Overridepublic void onPause(){ super.onPause(); if (mOpenCvCameraView != null) mOpenCvCameraView.disableView();}@Overridepublic void onResume(){ super.onResume(); if (mOpenCvCameraView != null) { mOpenCvCameraView.enableView(); mOpenCvCameraView.setOnTouchListener(MainActivity.this); }}public void ColorBlobDetectionActivity() { Log.i(TAG, "Instantiated new " + this.getClass());}@Overrideprotected List<? extends CameraBridgeViewBase> getCameraViewList() { return Collections.singletonList(mOpenCvCameraView);}public void onDestroy() { super.onDestroy(); if (mOpenCvCameraView != null) mOpenCvCameraView.disableView();}

}

运行效果

点击色块即可识别出该种颜色的区域
在这里插入图片描述

Android Studio使用OpenCV库

概要

在android添加OpenCV库,并运行自带色块识别例程

下载OpenCV包

https://opencv.org/releases/
下载opencv-4.9.0-android-sdk.zip并解压到一个目录(英文)

在Android Studio新建空工程

选择选择选择在这里插入图片描述选择Empty Activity,最小版本选择Android5.0

导入OpenCV库,选择sdk路径
在这里插入图片描述如果添加后提示kotlin-android错误,删掉build.gradle中的该句即可,修改compileSdkVersion,minSdkVersion,targetSdkVersion三个属性和工程保持一致

添加module依赖
在菜单file-》Project Structure窗口选择dependencies,选择sdk
在这里插入图片描述

测试加载OpenCV库

在activity的onCreate()调用

private void loadOpenCV() {    boolean success = OpenCVLoader.initDebug();   //对OpenCV库进行初始化加载,bool返回值可以判断是否加载成功。    if (success) {        Toast.makeText(this.getApplicationContext(), "OpenCV库加载成功", Toast.LENGTH_SHORT).show();    } else {        Toast.makeText(this.getApplicationContext(), "OpenCV库加载失败", Toast.LENGTH_SHORT).show();    }}

测试自带samples

将color-blob-detection下ColorBlobDetectionActivity.java和ColorBlobDetector.java拷贝到工程src下,修改activity的layout
在这里插入图片描述
MainActivity的完整代码如下:
package com.gaoda.cameracv;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import android.Manifest;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceView;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Toast;

import org.opencv.android.CameraActivity;
import org.opencv.android.CameraBridgeViewBase;
import org.opencv.android.OpenCVLoader;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfPoint;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewListener2;
import org.opencv.imgproc.Imgproc;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class MainActivity extends CameraActivity implements View.OnTouchListener, CvCameraViewListener2{
private static final String TAG = “MainActivity”;
private final int mRequestCode = 100;//权限请求码
List mPermissionList = new ArrayList<>();
String[] permissions = new String[]{
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.CAMERA,
Manifest.permission.INTERNET};

private boolean              mIsColorSelected = false;private Mat                  mRgba;private Scalar               mBlobColorRgba;private Scalar               mBlobColorHsv;private ColorBlobDetector    mDetector;private Mat                  mSpectrum;private Size                 SPECTRUM_SIZE;private Scalar               CONTOUR_COLOR;private CameraBridgeViewBase mOpenCvCameraView;@Overrideprotected void onCreate(Bundle savedInstanceState) {    Log.i(TAG, "called onCreate");    super.onCreate(savedInstanceState);    requestWindowFeature(Window.FEATURE_NO_TITLE);    getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);    setContentView(R.layout.activity_main);    initPermission();    mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.color_blob_detection_activity_surface_view);    mOpenCvCameraView.setVisibility(SurfaceView.VISIBLE);    mOpenCvCameraView.setCvCameraViewListener(this);}//初始化private void init(){    loadOpenCV();    //new TimeThread().start(); //启动新的线程}private void initPermission(){    int osVersion = Integer.valueOf(android.os.Build.VERSION.SDK);    if (osVersion>22) {        mPermissionList.clear();//清空已经允许的没有通过的权限        //逐个判断是否还有未通过的权限        for (int i = 0; i < permissions.length; i++) {            if (ContextCompat.checkSelfPermission(this, permissions[i]) !=                    PackageManager.PERMISSION_GRANTED) {                mPermissionList.add(permissions[i]);//添加还未授予的权限到mPermissionList中            }        }        //申请权限        if (mPermissionList.size() > 0) {//有权限没有通过,需要申请            ActivityCompat.requestPermissions(this, permissions, mRequestCode);} else {            //权限已经都通过了,可以将程序继续打开了            init();        }    }else        init();}/** * 5.请求权限后回调的方法 * @param requestCode 是我们自己定义的权限请求码 * @param permissions 是我们请求的权限名称数组 * @param grantResults 是我们在弹出页面后是否允许权限的标识数组,数组的长度对应的是权限 *                     名称数组的长度,数组的数据0表示允许权限,-1表示我们点击了禁止权限 */@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,                                       @NonNull int[] grantResults) {    super.onRequestPermissionsResult(requestCode, permissions, grantResults);    boolean hasPermissionDismiss = false;//有权限没有通过    if (mRequestCode==requestCode){        for (int i=0;i<grantResults.length;i++){            if (grantResults[i]==-1){                hasPermissionDismiss=true;                break;            }        }    }    if (hasPermissionDismiss){//如果有没有被允许的权限        showPermissionDialog();}else {        //权限已经都通过了,可以将程序继续打开了        init();    }}/** *  6.不再提示权限时的展示对话框 */AlertDialog mPermissionDialog;String mPackName = "com.gaoda.opencvtest";private void showPermissionDialog() {    if (mPermissionDialog == null) {        mPermissionDialog = new AlertDialog.Builder(this)                .setMessage("已禁用权限,请手动授予")                .setPositiveButton("设置", new DialogInterface.OnClickListener() {                    @Override                    public void onClick(DialogInterface dialog, int which) {                        cancelPermissionDialog();                        Uri packageURI = Uri.parse("package:" + mPackName);                        Intent intent = new Intent(Settings.                                ACTION_APPLICATION_DETAILS_SETTINGS, packageURI);                        startActivity(intent);                    }                })                .setNegativeButton("取消", new DialogInterface.OnClickListener() {                    @Override                    public void onClick(DialogInterface dialog, int which) {                        //关闭页面或者做其他操作                        cancelPermissionDialog();                        MainActivity.this.finish();                    }                })                .create();    }    mPermissionDialog.show();}private void cancelPermissionDialog() {    mPermissionDialog.cancel();}private void loadOpenCV() {    boolean success = OpenCVLoader.initDebug();   //对OpenCV库进行初始化加载,bool返回值可以判断是否加载成功。