在移動應用開發中,圖像處理是一個非常重要的領域。隨著智能手機攝像頭性能的不斷提升,開發者可以利用手機攝像頭進行各種復雜的圖像處理任務。OpenCV(Open Source Computer Vision Library)是一個開源的計算機視覺庫,提供了豐富的圖像處理功能。本文將詳細介紹如何在Android平臺上使用OpenCV4Android庫,通過手機攝像頭獲取Canny邊緣。
OpenCV4Android是OpenCV庫的Android版本,專門為Android平臺優化。它提供了Java和C++接口,開發者可以根據需求選擇合適的接口進行開發。OpenCV4Android支持多種圖像處理算法,包括邊緣檢測、特征提取、目標跟蹤等。
首先,確保你已經安裝了Android Studio。Android Studio是Google官方推薦的Android應用開發工具,提供了強大的代碼編輯、調試和性能分析功能。
opencv-android-sdk
文件夾。Start a new Android Studio project
。Empty Activity
模板,點擊Next
。OpenCVCannyEdgeDetection
,選擇保存路徑,點擊Finish
。File
-> New
-> Import Module
。opencv-android-sdk/sdk/java
路徑,點擊Finish
。build.gradle
文件中添加OpenCV庫的依賴:
dependencies {
implementation project(':opencv')
}
在AndroidManifest.xml文件中添加攝像頭權限:
<uses-permission android:name="android.permission.CAMERA" />
MainActivity.java
中,添加攝像頭初始化代碼:
“`java
import android.Manifest;
import android.content.pm.PackageManager;
import android.hardware.Camera;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.SurfaceView;
import android.widget.FrameLayout;public class MainActivity extends AppCompatActivity { private Camera mCamera; private SurfaceView mPreview; private FrameLayout mFrameLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mFrameLayout = findViewById(R.id.camera_preview);
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 1);
} else {
initializeCamera();
}
}
private void initializeCamera() {
mCamera = Camera.open();
mPreview = new CameraPreview(this, mCamera);
mFrameLayout.addView(mPreview);
}
}
2. 創建`CameraPreview`類,用于顯示攝像頭預覽:
```java
import android.content.Context;
import android.hardware.Camera;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
public CameraPreview(Context context, Camera camera) {
super(context);
mCamera = camera;
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (mHolder.getSurface() == null) {
return;
}
try {
mCamera.stopPreview();
} catch (Exception e) {
e.printStackTrace();
}
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// Release the camera preview
}
}
MainActivity.java
中,添加圖像捕獲代碼:
“`java
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.hardware.Camera;
import android.os.Environment;
import android.util.Log;
import android.widget.ImageView;public class MainActivity extends AppCompatActivity { private Camera mCamera; private SurfaceView mPreview; private FrameLayout mFrameLayout; private ImageView mImageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mFrameLayout = findViewById(R.id.camera_preview);
mImageView = findViewById(R.id.image_view);
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 1);
} else {
initializeCamera();
}
}
private void initializeCamera() {
mCamera = Camera.open();
mPreview = new CameraPreview(this, mCamera);
mFrameLayout.addView(mPreview);
mCamera.setPreviewCallback(new Camera.PreviewCallback() {
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
Camera.Size size = camera.getParameters().getPreviewSize();
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
mImageView.setImageBitmap(bitmap);
}
});
}
}
### Canny邊緣檢測算法
Canny邊緣檢測是一種多階段的邊緣檢測算法,主要包括以下幾個步驟:
1. 高斯濾波:去除圖像噪聲。
2. 計算梯度:使用Sobel算子計算圖像的梯度幅值和方向。
3. 非極大值抑制:保留梯度幅值最大的像素,抑制其他像素。
4. 雙閾值檢測:通過高低閾值確定邊緣。
### 實現Canny邊緣檢測
1. 在`MainActivity.java`中,添加Canny邊緣檢測代碼:
```java
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.android.Utils;
import org.opencv.imgproc.Imgproc;
public class MainActivity extends AppCompatActivity {
private Camera mCamera;
private SurfaceView mPreview;
private FrameLayout mFrameLayout;
private ImageView mImageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mFrameLayout = findViewById(R.id.camera_preview);
mImageView = findViewById(R.id.image_view);
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 1);
} else {
initializeCamera();
}
}
private void initializeCamera() {
mCamera = Camera.open();
mPreview = new CameraPreview(this, mCamera);
mFrameLayout.addView(mPreview);
mCamera.setPreviewCallback(new Camera.PreviewCallback() {
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
Camera.Size size = camera.getParameters().getPreviewSize();
Mat rgba = new Mat(size.height, size.width, CvType.CV_8UC4);
Mat gray = new Mat(size.height, size.width, CvType.CV_8UC1);
Mat edges = new Mat(size.height, size.width, CvType.CV_8UC1);
Utils.bitmapToMat(BitmapFactory.decodeByteArray(data, 0, data.length), rgba);
Imgproc.cvtColor(rgba, gray, Imgproc.COLOR_RGBA2GRAY);
Imgproc.Canny(gray, edges, 50, 150);
Bitmap resultBitmap = Bitmap.createBitmap(edges.cols(), edges.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(edges, resultBitmap);
mImageView.setImageBitmap(resultBitmap);
}
});
}
}
為了提升性能,可以降低圖像的分辨率。在Camera.Parameters
中設置預覽尺寸:
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(640, 480);
mCamera.setParameters(parameters);
為了避免UI線程阻塞,可以將圖像處理任務放在后臺線程中執行:
private class ImageProcessingTask extends AsyncTask<byte[], Void, Bitmap> {
@Override
protected Bitmap doInBackground(byte[]... data) {
Camera.Size size = mCamera.getParameters().getPreviewSize();
Mat rgba = new Mat(size.height, size.width, CvType.CV_8UC4);
Mat gray = new Mat(size.height, size.width, CvType.CV_8UC1);
Mat edges = new Mat(size.height, size.width, CvType.CV_8UC1);
Utils.bitmapToMat(BitmapFactory.decodeByteArray(data[0], 0, data[0].length), rgba);
Imgproc.cvtColor(rgba, gray, Imgproc.COLOR_RGBA2GRAY);
Imgproc.Canny(gray, edges, 50, 150);
Bitmap resultBitmap = Bitmap.createBitmap(edges.cols(), edges.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(edges, resultBitmap);
return resultBitmap;
}
@Override
protected void onPostExecute(Bitmap resultBitmap) {
mImageView.setImageBitmap(resultBitmap);
}
}
本文詳細介紹了如何在Android平臺上使用OpenCV4Android庫,通過手機攝像頭獲取Canny邊緣。從環境搭建、項目創建、攝像頭初始化到圖像處理和Canny邊緣檢測的實現,涵蓋了整個開發流程。通過優化圖像分辨率和多線程處理,可以顯著提升應用的性能。希望本文能為你在Android圖像處理開發中提供有價值的參考。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。