Android Studio中OpenCV應用詳解:圖像處理、顏色對比與OCR識別

文章目錄

    • 一、OpenCV在Android中的集成與配置
      • 1.1 OpenCV簡介
      • 1.2 在Android Studio中集成OpenCV
        • 1.2.1 通過Gradle依賴集成
        • 1.2.2 通過模塊方式集成
        • 1.2.3 初始化OpenCV
      • 1.3 OpenCV基礎類介紹
    • 二、指定區域圖像抓取與對比
      • 2.1 圖像抓取基礎
      • 2.2 指定區域圖像抓取實現
        • 2.2.1 從Bitmap中截取指定區域
        • 2.2.2 使用OpenCV截取指定區域
      • 2.3 圖像對比技術
        • 2.3.1 均方誤差(MSE)對比
        • 2.3.2 結構相似性(SSIM)對比
        • 2.3.3 特征點匹配對比
      • 2.4 圖像對比應用實例
        • 2.4.1 圖像相似度檢測
        • 2.4.2 圖像差異可視化
    • 三、指定點顏色提取與對比
      • 3.1 顏色空間基礎
      • 3.2 指定點顏色提取
        • 3.2.1 從Bitmap中獲取像素顏色
        • 3.2.2 使用OpenCV獲取像素顏色
      • 3.3 顏色空間轉換
      • 3.4 顏色對比技術
        • 3.4.1 歐氏距離顏色對比
        • 3.4.2 CIEDE2000顏色差異算法
        • 3.4.3 顏色相似度判斷
      • 3.5 顏色對比應用實例
        • 3.5.1 屏幕取色器實現
        • 3.5.2 顏色匹配檢測
    • 四、指定區域OCR內容提取
      • 4.1 OCR技術簡介
      • 4.2 Tesseract OCR集成
        • 4.2.1 添加Tesseract依賴
        • 4.2.2 初始化Tesseract
      • 4.3 圖像預處理優化OCR結果
        • 4.3.1 基本預處理流程
        • 4.3.2 高級預處理技術
      • 4.4 指定區域OCR實現
        • 4.4.1 從指定區域提取文本

一、OpenCV在Android中的集成與配置

1.1 OpenCV簡介

OpenCV(Open Source Computer Vision Library)是一個開源的計算機視覺和機器學習軟件庫,包含超過2500種優化算法,涵蓋圖像處理、模式識別、機器學習等眾多領域。在Android平臺上,OpenCV為開發者提供了強大的圖像處理能力,可以用于實現各種復雜的計算機視覺應用。

1.2 在Android Studio中集成OpenCV

1.2.1 通過Gradle依賴集成

最簡單的方式是通過Gradle添加OpenCV依賴:

dependencies {implementation 'org.opencv:opencv-android:4.5.5'
}
1.2.2 通過模塊方式集成

更靈活的方式是下載OpenCV Android SDK并將其作為模塊導入:

  1. 從OpenCV官網下載Android SDK
  2. 在Android Studio中選擇File -> New -> Import Module
  3. 選擇OpenCV SDK中的java文件夾
  4. 修改模塊的build.gradle文件,確保與主項目兼容
1.2.3 初始化OpenCV

在應用啟動時需要初始化OpenCV庫:

public class MainActivity extends AppCompatActivity {private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {@Overridepublic void onManagerConnected(int status) {if (status == LoaderCallbackInterface.SUCCESS) {Log.i("OpenCV", "OpenCV loaded successfully");} else {super.onManagerConnected(status);}}};@Overrideprotected void onResume() {super.onResume();if (!OpenCVLoader.initDebug()) {OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_0_0, this, mLoaderCallback);} else {mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);}}
}

1.3 OpenCV基礎類介紹

在Android中使用OpenCV主要涉及以下幾個核心類:

  1. Mat:OpenCV的基礎矩陣類,用于存儲圖像數據
  2. Bitmap:Android的位圖類,需要與Mat相互轉換
  3. Imgproc:圖像處理類,包含各種圖像處理算法
  4. Core:核心功能類,提供基本數學運算和矩陣操作
  5. Feature2d:特征檢測與描述類

二、指定區域圖像抓取與對比

2.1 圖像抓取基礎

在Android中獲取圖像主要有以下幾種方式:

  1. 從相機捕獲
  2. 從圖庫選擇
  3. 從資源文件加載
  4. 從網絡下載

2.2 指定區域圖像抓取實現

2.2.1 從Bitmap中截取指定區域
public static Bitmap cropBitmap(Bitmap srcBitmap, Rect region) {if (srcBitmap == null || region == null) return null;try {// 確保區域在圖像范圍內int x = Math.max(0, region.left);int y = Math.max(0, region.top);int width = Math.min(srcBitmap.getWidth() - x, region.width());int height = Math.min(srcBitmap.getHeight() - y, region.height());return Bitmap.createBitmap(srcBitmap, x, y, width, height);} catch (Exception e) {e.printStackTrace();return null;}
}
2.2.2 使用OpenCV截取指定區域
public static Mat cropImage(Mat srcMat, Rect roi) {if (srcMat.empty() || roi == null) return null;try {// 確保ROI在圖像范圍內Rect adjustedRoi = new Rect(Math.max(0, roi.x),Math.max(0, roi.y),Math.min(srcMat.cols() - roi.x, roi.width),Math.min(srcMat.rows() - roi.y, roi.height));return new Mat(srcMat, adjustedRoi);} catch (Exception e) {e.printStackTrace();return new Mat();}
}

2.3 圖像對比技術

2.3.1 均方誤差(MSE)對比
public static double compareImagesMSE(Mat img1, Mat img2) {if (img1.rows() != img2.rows() || img1.cols() != img2.cols()) {throw new IllegalArgumentException("Images must have same dimensions");}Mat diff = new Mat();Core.absdiff(img1, img2, diff);diff.convertTo(diff, CvType.CV_32F);diff = diff.mul(diff);Scalar mse = Core.mean(diff);return (mse.val[0] + mse.val[1] + mse.val[2]) / 3;
}
2.3.2 結構相似性(SSIM)對比
public static double compareImagesSSIM(Mat img1, Mat img2) {// 轉換為灰度圖像Mat gray1 = new Mat();Mat gray2 = new Mat();Imgproc.cvtColor(img1, gray1, Imgproc.COLOR_BGR2GRAY);Imgproc.cvtColor(img2, gray2, Imgproc.COLOR_BGR2GRAY);// 參數設置final double C1 = 6.5025, C2 = 58.5225;int d = CvType.CV_32F;Mat I1 = new Mat(), I2 = new Mat();gray1.convertTo(I1, d);gray2.convertTo(I2, d);Mat I1_2 = I1.mul(I1);Mat I2_2 = I2.mul(I2);Mat I1_I2 = I1.mul(I2);// 計算均值Mat mu1 = new Mat(), mu2 = new Mat();Imgproc.GaussianBlur(I1, mu1, new Size(11, 11), 1.5);Imgproc.GaussianBlur(I2, mu2, new Size(11, 11), 1.5);Mat mu1_2 = mu1.mul(mu1);Mat mu2_2 = mu2.mul(mu2);Mat mu1_mu2 = mu1.mul(mu2);// 計算方差Mat sigma1_2 = new Mat(), sigma2_2 = new Mat(), sigma12 = new Mat();Imgproc.GaussianBlur(I1_2, sigma1_2, new Size(11, 11), 1.5);Core.subtract(sigma1_2, mu1_2, sigma1_2);Imgproc.GaussianBlur(I2_2, sigma2_2, new Size(11, 11), 1.5);Core.subtract(sigma2_2, mu2_2, sigma2_2);Imgproc.GaussianBlur(I1_I2, sigma12, new Size(11, 11), 1.5);Core.subtract(sigma12, mu1_mu2, sigma12);// 計算SSIMMat t1 = new Mat(), t2 = new Mat(), t3 = new Mat();Core.multiply(mu1_mu2, new Scalar(2), t1);Core.add(t1, new Scalar(C1), t1);Core.multiply(sigma12, new Scalar(2), t2);Core.add(t2, new Scalar(C2), t2);Core.add(mu1_2, mu2_2, t3);Core.add(t3, new Scalar(C1), t3);Mat ssim_map = new Mat();Core.multiply(t1, t2, ssim_map);Core.divide(ssim_map, t3, ssim_map);Scalar mssim = Core.mean(ssim_map);return mssim.val[0];
}
2.3.3 特征點匹配對比
public static double compareImagesFeatureMatching(Mat img1, Mat img2) {// 轉換為灰度圖像Mat gray1 = new Mat();Mat gray2 = new Mat();Imgproc.cvtColor(img1, gray1, Imgproc.COLOR_BGR2GRAY);Imgproc.cvtColor(img2, gray2, Imgproc.COLOR_BGR2GRAY);// 檢測ORB特征點ORB orb = ORB.create();MatOfKeyPoint keypoints1 = new MatOfKeyPoint();MatOfKeyPoint keypoints2 = new MatOfKeyPoint();Mat descriptors1 = new Mat();Mat descriptors2 = new Mat();orb.detectAndCompute(gray1, new Mat(), keypoints1, descriptors1);orb.detectAndCompute(gray2, new Mat(), keypoints2, descriptors2);// 使用BFMatcher進行匹配BFMatcher matcher = BFMatcher.create(BFMatcher.BRUTEFORCE_HAMMING);MatOfDMatch matches = new MatOfDMatch();matcher.match(descriptors1, descriptors2, matches);// 計算匹配質量List<DMatch> matchesList = matches.toList();double maxDist = 0;double minDist = 100;for (DMatch match : matchesList) {double dist = match.distance;if (dist < minDist) minDist = dist;if (dist > maxDist) maxDist = dist;}// 篩選好的匹配點List<DMatch> goodMatches = new ArrayList<>();for (DMatch match : matchesList) {if (match.distance <= Math.max(2 * minDist, 30.0)) {goodMatches.add(match);}}// 計算匹配率double matchRatio = (double)goodMatches.size() / matchesList.size();return matchRatio;
}

2.4 圖像對比應用實例

2.4.1 圖像相似度檢測
public class ImageComparator {private static final double MSE_THRESHOLD = 1000;private static final double SSIM_THRESHOLD = 0.8;private static final double FEATURE_MATCH_THRESHOLD = 0.5;public enum ComparisonResult {VERY_SIMILAR,SIMILAR,DIFFERENT,INVALID}public static ComparisonResult compareImages(Bitmap bmp1, Bitmap bmp2, Rect roi1, Rect roi2) {try {// 轉換Bitmap為MatMat mat1 = new Mat();Mat mat2 = new Mat();Utils.bitmapToMat(bmp1, mat1);Utils.bitmapToMat(bmp2, mat2);// 裁剪指定區域Mat cropped1 = cropImage(mat1, roi1);Mat cropped2 = cropImage(mat2, roi2);if (cropped1.empty() || cropped2.empty()) {return ComparisonResult.INVALID;}// 調整大小一致if (cropped1.size().width != cropped2.size().width || cropped1.size().height != cropped2.size().height) {Imgproc.resize(cropped2, cropped2, cropped1.size());}// 計算各種相似度指標double mse = compareImagesMSE(cropped1, cropped2);double ssim = compareImagesSSIM(cropped1, cropped2);double featureMatch = compareImagesFeatureMatching(cropped1, cropped2);// 綜合判斷if (mse < MSE_THRESHOLD && ssim > SSIM_THRESHOLD && featureMatch > FEATURE_MATCH_THRESHOLD) {return ComparisonResult.VERY_SIMILAR;} else if (ssim > SSIM_THRESHOLD || featureMatch > FEATURE_MATCH_THRESHOLD) {return ComparisonResult.SIMILAR;} else {return ComparisonResult.DIFFERENT;}} catch (Exception e) {e.printStackTrace();return ComparisonResult.INVALID;}}
}
2.4.2 圖像差異可視化
public static Bitmap visualizeImageDifference(Bitmap bmp1, Bitmap bmp2) {try {// 轉換Bitmap為MatMat mat1 = new Mat();Mat mat2 = new Mat();Utils.bitmapToMat(bmp1, mat1);Utils.bitmapToMat(bmp2, mat2);// 確保圖像大小一致if (mat1.size().width != mat2.size().width || mat1.size().height != mat2.size().height) {Imgproc.resize(mat2, mat2, mat1.size());}// 計算差異Mat diff = new Mat();Core.absdiff(mat1, mat2, diff);// 增強差異可視化Core.normalize(diff, diff, 0, 255, Core.NORM_MINMAX);Imgproc.cvtColor(diff, diff, Imgproc.COLOR_BGR2RGB);// 轉換回BitmapBitmap result = Bitmap.createBitmap(diff.cols(), diff.rows(), Bitmap.Config.ARGB_8888);Utils.matToBitmap(diff, result);return result;} catch (Exception e) {e.printStackTrace();return null;}
}

三、指定點顏色提取與對比

3.1 顏色空間基礎

OpenCV支持多種顏色空間,常用的有:

  1. RGB/BGR:默認顏色空間
  2. HSV/HSL:色調、飽和度、亮度/明度
  3. Lab:感知均勻的顏色空間
  4. YCrCb:亮度和色度分量
  5. Grayscale:灰度圖像

3.2 指定點顏色提取

3.2.1 從Bitmap中獲取像素顏色
public static int getPixelColor(Bitmap bitmap, int x, int y) {if (bitmap == null || x < 0 || y < 0 || x >= bitmap.getWidth() || y >= bitmap.getHeight()) {return 0;}return bitmap.getPixel(x, y);
}public static int[] getPixelColorARGB(Bitmap bitmap, int x, int y) {int pixel = getPixelColor(bitmap, x, y);return new int[] {(pixel >> 24) & 0xff, // Alpha(pixel >> 16) & 0xff, // Red(pixel >> 8) & 0xff,  // Greenpixel & 0xff          // Blue};
}
3.2.2 使用OpenCV獲取像素顏色
public static double[] getPixelColor(Mat mat, int x, int y) {if (mat.empty() || x < 0 || y < 0 || x >= mat.cols() || y >= mat.rows()) {return new double[]{0, 0, 0};}double[] pixel = mat.get(y, x); // OpenCV中使用(row, col)順序return pixel;
}public static Scalar getPixelColorScalar(Mat mat, int x, int y) {double[] pixel = getPixelColor(mat, x, y);if (pixel == null || pixel.length < 3) {return new Scalar(0, 0, 0);}return new Scalar(pixel[0], pixel[1], pixel[2]);
}

3.3 顏色空間轉換

public static Mat convertColorSpace(Mat src, int conversionCode) {if (src.empty()) return new Mat();Mat dst = new Mat();try {Imgproc.cvtColor(src, dst, conversionCode);} catch (Exception e) {e.printStackTrace();}return dst;
}// 常用顏色空間轉換代碼
public static final int COLOR_BGR2RGB = Imgproc.COLOR_BGR2RGB;
public static final int COLOR_BGR2HSV = Imgproc.COLOR_BGR2HSV;
public static final int COLOR_BGR2Lab = Imgproc.COLOR_BGR2Lab;
public static final int COLOR_BGR2YCrCb = Imgproc.COLOR_BGR2YCrCb;
public static final int COLOR_BGR2GRAY = Imgproc.COLOR_BGR2GRAY;

3.4 顏色對比技術

3.4.1 歐氏距離顏色對比
public static double colorDistanceEuclidean(Scalar color1, Scalar color2) {double diffR = color1.val[0] - color2.val[0];double diffG = color1.val[1] - color2.val[1];double diffB = color1.val[2] - color2.val[2];return Math.sqrt(diffR * diffR + diffG * diffG + diffB * diffB);
}
3.4.2 CIEDE2000顏色差異算法
// 需要實現Lab顏色空間的Delta E計算
public static double colorDistanceCIEDE2000(Scalar lab1, Scalar lab2) {// 簡化的Delta E 2000計算double L1 = lab1.val[0];double a1 = lab1.val[1];double b1 = lab1.val[2];double L2 = lab2.val[0];double a2 = lab2.val[1];double b2 = lab2.val[2];double deltaL = L2 - L1;double meanL = (L1 + L2) / 2;double C1 = Math.sqrt(a1 * a1 + b1 * b1);double C2 = Math.sqrt(a2 * a2 + b2 * b2);double meanC = (C1 + C2) / 2;double G = 0.5 * (1 - Math.sqrt(Math.pow(meanC, 7) / (Math.pow(meanC, 7) + Math.pow(25, 7))));double a1Prime = a1 * (1 + G);double a2Prime = a2 * (1 + G);double C1Prime = Math.sqrt(a1Prime * a1Prime + b1 * b1);double C2Prime = Math.sqrt(a2Prime * a2Prime + b2 * b2);double meanCPrime = (C1Prime + C2Prime) / 2;double h1Prime = Math.toDegrees(Math.atan2(b1, a1Prime));if (h1Prime < 0) h1Prime += 360;double h2Prime = Math.toDegrees(Math.atan2(b2, a2Prime));if (h2Prime < 0) h2Prime += 360;double deltaHPrime;if (Math.abs(h1Prime - h2Prime) <= 180) {deltaHPrime = h2Prime - h1Prime;} else if (h2Prime <= h1Prime) {deltaHPrime = h2Prime - h1Prime + 360;} else {deltaHPrime = h2Prime - h1Prime - 360;}double deltaH = 2 * Math.sqrt(C1Prime * C2Prime) * Math.sin(Math.toRadians(deltaHPrime / 2));double meanHPrime;if (Math.abs(h1Prime - h2Prime) <= 180) {meanHPrime = (h1Prime + h2Prime) / 2;} else if (h1Prime + h2Prime < 360) {meanHPrime = (h1Prime + h2Prime + 360) / 2;} else {meanHPrime = (h1Prime + h2Prime - 360) / 2;}double T = 1 - 0.17 * Math.cos(Math.toRadians(meanHPrime - 30))+ 0.24 * Math.cos(Math.toRadians(2 * meanHPrime))+ 0.32 * Math.cos(Math.toRadians(3 * meanHPrime + 6))- 0.20 * Math.cos(Math.toRadians(4 * meanHPrime - 63));double SL = 1 + (0.015 * Math.pow(meanL - 50, 2)) / Math.sqrt(20 + Math.pow(meanL - 50, 2));double SC = 1 + 0.045 * meanCPrime;double SH = 1 + 0.015 * meanCPrime * T;double RT = -2 * Math.sqrt(Math.pow(meanCPrime, 7) / (Math.pow(meanCPrime, 7) + Math.pow(25, 7)))* Math.sin(Math.toRadians(60 * Math.exp(-Math.pow((meanHPrime - 275) / 25, 2))));double deltaE = Math.sqrt(Math.pow(deltaL / SL, 2)+ Math.pow(deltaHPrime / SC, 2)+ Math.pow(deltaH / SH, 2)+ RT * (deltaCPrime / SC) * (deltaH / SH));return deltaE;
}
3.4.3 顏色相似度判斷
public static boolean areColorsSimilar(Scalar color1, Scalar color2, double threshold, int colorSpace) {// 轉換為指定顏色空間Mat mat1 = new Mat(1, 1, CvType.CV_8UC3, color1);Mat mat2 = new Mat(1, 1, CvType.CV_8UC3, color2);if (colorSpace != Imgproc.COLOR_BGR2RGB) {Imgproc.cvtColor(mat1, mat1, colorSpace);Imgproc.cvtColor(mat2, mat2, colorSpace);}Scalar c1 = new Scalar(mat1.get(0, 0));Scalar c2 = new Scalar(mat2.get(0, 0));// 根據顏色空間選擇合適的比較方法if (colorSpace == Imgproc.COLOR_BGR2Lab) {double deltaE = colorDistanceCIEDE2000(c1, c2);return deltaE < threshold;} else {double distance = colorDistanceEuclidean(c1, c2);return distance < threshold;}
}

3.5 顏色對比應用實例

3.5.1 屏幕取色器實現
public class ColorPickerView extends View {private Bitmap mBitmap;private int mSelectedX = -1;private int mSelectedY = -1;private OnColorSelectedListener mListener;public interface OnColorSelectedListener {void onColorSelected(int color);}public ColorPickerView(Context context) {super(context);}public ColorPickerView(Context context, AttributeSet attrs) {super(context, attrs);}public void setBitmap(Bitmap bitmap) {mBitmap = bitmap;invalidate();}public void setOnColorSelectedListener(OnColorSelectedListener listener) {mListener = listener;}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);if (mBitmap != null) {// 繪制圖像Rect src = new Rect(0, 0, mBitmap.getWidth(), mBitmap.getHeight());Rect dst = new Rect(0, 0, getWidth(), getHeight());canvas.drawBitmap(mBitmap, src, dst, null);// 繪制選擇點標記if (mSelectedX >= 0 && mSelectedY >= 0) {Paint paint = new Paint();paint.setColor(Color.WHITE);paint.setStyle(Paint.Style.STROKE);paint.setStrokeWidth(3);canvas.drawCircle(mSelectedX, mSelectedY, 20, paint);// 獲取并顯示顏色值int color = getPixelColor(mBitmap, mSelectedX, mSelectedY);paint.setStyle(Paint.Style.FILL);paint.setColor(color);canvas.drawRect(getWidth() - 100, 20, getWidth() - 20, 100, paint);paint.setColor(Color.BLACK);paint.setTextSize(30);canvas.drawText(String.format("#%06X", (0xFFFFFF & color)), getWidth() - 180, 70, paint);}}}@Overridepublic boolean onTouchEvent(MotionEvent event) {if (mBitmap == null) return super.onTouchEvent(event);int x = (int)(event.getX() * mBitmap.getWidth() / getWidth());int y = (int)(event.getY() * mBitmap.getHeight() / getHeight());if (x >= 0 && x < mBitmap.getWidth() && y >= 0 && y < mBitmap.getHeight()) {mSelectedX = x;mSelectedY = y;if (mListener != null) {int color = getPixelColor(mBitmap, x, y);mListener.onColorSelected(color);}invalidate();return true;}return super.onTouchEvent(event);}private int getPixelColor(Bitmap bitmap, int x, int y) {if (x < 0 || y < 0 || x >= bitmap.getWidth() || y >= bitmap.getHeight()) {return Color.TRANSPARENT;}return bitmap.getPixel(x, y);}
}
3.5.2 顏色匹配檢測
public class ColorMatchDetector {private Scalar mTargetColor;private double mThreshold;private int mColorSpace;public ColorMatchDetector(Scalar targetColor, double threshold, int colorSpace) {mTargetColor = targetColor;mThreshold = threshold;mColorSpace = colorSpace;}public Mat findColorRegions(Mat inputImage) {// 轉換為目標顏色空間Mat converted = new Mat();Imgproc.cvtColor(inputImage, converted, mColorSpace);// 創建目標顏色矩陣Mat targetMat = new Mat(inputImage.size(), converted.type(), mTargetColor);// 計算差異Mat diff = new Mat();Core.absdiff(converted, targetMat, diff);// 分割通道List<Mat> channels = new ArrayList<>();Core.split(diff, channels);// 計算總差異Mat totalDiff = new Mat(channels.get(0).size(), CvType.CV_32F);for (Mat channel : channels) {Mat floatChannel = new Mat();channel.convertTo(floatChannel, CvType.CV_32F);Core.add(totalDiff, floatChannel.mul(floatChannel), totalDiff);}Core.sqrt(totalDiff, totalDiff);// 創建掩碼Mat mask = new Mat();Core.inRange(totalDiff, new Scalar(0), new Scalar(mThreshold), mask);// 清理小區域Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, new Size(5, 5));Imgproc.morphologyEx(mask, mask, Imgproc.MORPH_OPEN, kernel);Imgproc.morphologyEx(mask, mask, Imgproc.MORPH_CLOSE, kernel);return mask;}public List<Rect> findColorContours(Mat inputImage) {Mat mask = findColorRegions(inputImage);// 查找輪廓List<MatOfPoint> contours = new ArrayList<>();Mat hierarchy = new Mat();Imgproc.findContours(mask, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);// 轉換為矩形List<Rect> rects = new ArrayList<>();for (MatOfPoint contour : contours) {Rect rect = Imgproc.boundingRect(contour);if (rect.area() > 100) { // 忽略小區域rects.add(rect);}}return rects;}
}

四、指定區域OCR內容提取

4.1 OCR技術簡介

OCR(Optical Character Recognition,光學字符識別)是將圖像中的文字轉換為可編輯文本的技術。在Android中實現OCR通常有以下幾種方式:

  1. 使用Tesseract OCR引擎
  2. 使用Google ML Kit文本識別API
  3. 使用第三方OCR服務API

4.2 Tesseract OCR集成

4.2.1 添加Tesseract依賴

在build.gradle中添加:

dependencies {implementation 'com.rmtheis:tess-two:9.1.0'
}
4.2.2 初始化Tesseract
public class TessOCR {private TessBaseAPI mTess;public TessOCR(Context context, String language) {mTess = new TessBaseAPI();// 訓練數據路徑String datapath = context.getFilesDir() + "/tesseract/";File dir = new File(datapath + "tessdata/");if (!dir.exists()) {dir.mkdirs();}// 檢查訓練數據文件是否存在File tessdataFile = new File(datapath + "tessdata/" + language + ".traineddata");if (!tessdataFile.exists()) {try {// 從assets復制訓練數據InputStream in = context.getAssets().open("tessdata/" + language + ".traineddata");OutputStream out = new FileOutputStream(tessdataFile);byte[] buffer = new byte[1024];int read;while ((read = in.read(buffer)) != -1) {out.write(buffer, 0, read);}in.close();out.flush();out.close();} catch (IOException e) {e.printStackTrace();}}mTess.init(datapath, language);}public String recognizeText(Bitmap bitmap) {if (bitmap == null) return "";mTess.setImage(bitmap);return mTess.getUTF8Text();}public String recognizeText(Mat mat) {if (mat.empty()) return "";Bitmap bitmap = Bitmap.createBitmap(mat.cols(), mat.rows(), Bitmap.Config.ARGB_8888);Utils.matToBitmap(mat, bitmap);return recognizeText(bitmap);}public void destroy() {if (mTess != null) {mTess.end();}}
}

4.3 圖像預處理優化OCR結果

4.3.1 基本預處理流程
public static Mat prepareImageForOCR(Mat src) {if (src.empty()) return new Mat();Mat processed = new Mat();// 1. 轉換為灰度圖像Imgproc.cvtColor(src, processed, Imgproc.COLOR_BGR2GRAY);// 2. 應用自適應閾值Imgproc.adaptiveThreshold(processed, processed, 255, Imgproc.ADAPTIVE_THRESH_GAUSSIAN_C,Imgproc.THRESH_BINARY, 11, 2);// 3. 降噪Imgproc.medianBlur(processed, processed, 3);// 4. 銳化Mat kernel = new Mat(3, 3, CvType.CV_32F) {{put(0, 0, 0);put(0, 1, -1);put(0, 2, 0);put(1, 0, -1);put(1, 1, 5);put(1, 2, -1);put(2, 0, 0);put(2, 1, -1);put(2, 2, 0);}};Imgproc.filter2D(processed, processed, -1, kernel);return processed;
}
4.3.2 高級預處理技術
public static Mat advancedOCRPreprocessing(Mat src) {if (src.empty()) return new Mat();Mat processed = new Mat();// 1. 轉換為灰度圖像Imgproc.cvtColor(src, processed, Imgproc.COLOR_BGR2GRAY);// 2. 應用CLAHE (對比度受限的自適應直方圖均衡化)CLAHE clahe = Imgproc.createCLAHE();clahe.setClipLimit(2);clahe.apply(processed, processed);// 3. 非局部均值去噪Photo.fastNlMeansDenoising(processed, processed, 10, 7, 21);// 4. 邊緣增強Mat edges = new Mat();Imgproc.Sobel(processed, edges, CvType.CV_8U, 1, 1);Core.add(processed, edges, processed);// 5. 局部自適應閾值Imgproc.adaptiveThreshold(processed, processed, 255, Imgproc.ADAPTIVE_THRESH_GAUSSIAN_C,Imgproc.THRESH_BINARY, 15, 5);// 6. 形態學操作去除小噪點Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(2, 2));Imgproc.morphologyEx(processed, processed, Imgproc.MORPH_OPEN, kernel);return processed;
}

4.4 指定區域OCR實現

4.4.1 從指定區域提取文本
public class RegionOCR {private TessOCR mTessOCR;public RegionOCR(Context context, String language) {mTessOCR = new TessOCR(context, language);}public String extractTextFromRegion(Bitmap srcBitmap, Rect region) {if (srcBitmap == null || region == null) return "";// 裁剪指定區域Bitmap cropped = Bitmap.createBitmap(srcBitmap, region.left, region.top,region.width(), region.height());// 預處理圖像Mat mat = new Mat();Utils.bitmapToMat(cropped, mat);mat = prepareImageForOCR(mat);// 執行OCRreturn mTessOCR.recognizeText(mat);}public String extractTextFromRegion(Mat srcMat, Rect region) {if (srcMat.empty() || region == null) return "";// 調整區域確保在圖像范圍內Rect adjusted = new Rect(Math.max(0, region.x),Math.max(0, region.y),Math.min(srcMat.cols() - region.x, region.width),Math.min(srcMat.rows() - region.y, region.height));// 裁剪指定區域Mat cropped = new Mat(srcMat, adjusted);// 預處理圖像Mat processed = prepareImageForOCR(cropped);// 執行OCRreturn mTessOCR.recognizeText(processed);}public void destroy() {if (mTessOCR != null) {mTessOCR.destroy();}}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/78259.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/78259.shtml
英文地址,請注明出處:http://en.pswp.cn/web/78259.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

前端面試每日三題 - Day 22

今天我們將深入探討 JavaScript 中的 Set 和 Map 數據結構&#xff0c;了解它們的特性及應用場景。接下來&#xff0c;我們會分析 React 的 Suspense 和 Concurrent Mode 的工作原理&#xff0c;探索它們如何提升應用的性能和用戶體驗。最后&#xff0c;我們將學習如何設計一個…

[Vue]編程式導航

在 Vue 中&#xff0c;編程式導航是通過 JavaScript 代碼&#xff08;而非 <router-link> 標簽&#xff09;動態控制路由跳轉的核心方式。這個方法依賴于 Vue Router 提供的 API&#xff0c;能更靈活地處理復雜場景&#xff08;如異步操作、條件跳轉等&#xff09;。 一、…

鄒曉輝教授十余年前關于圍棋程序與融智學的思考,體現了對復雜系統本質的深刻洞察,其觀點在人工智能發展歷程中具有前瞻性意義。我們可以從以下三個維度進行深入解析:

鄒曉輝教授十余年前關于圍棋程序與融智學的思考&#xff0c;體現了對復雜系統本質的深刻洞察&#xff0c;其觀點在人工智能發展歷程中具有前瞻性意義。我們可以從以下三個維度進行深入解析&#xff1a; 一、圍棋程序的二元解構&#xff1a;數據結構與算法的辯證關系 1.1.形式…

The Traitor King (10 player 25 player)

The Traitor King 十字軍試煉尾王成就。叛變的國王&#xff1a;在30秒內殺死40只蟲群甲蟲。考驗團隊配合的成就。比不朽者&#xff0c;黑曜石31等等強度大&#xff0c;甚至感覺比寶庫地風火難。

數據結構一 單鏈表

1.單鏈表 1.數據結構簡介 程序數據結構算法 數據 數據&#xff08;data&#xff09;是客觀事物的一個符號表示 數據元素&#xff08;data element&#xff09;是數據的基本單位&#xff0c;一 個數據元素可以由若干個數據項&#xff08;data item&#xff09;組成。數據項…

GPU集群監控系統開發實錄:基于Prometheus+Grafana的算力利用率可視化方案

一、科研場景下的GPU監控痛點 在深度學習模型訓練、分子動力學模擬等科研場景中&#xff0c;GPU集群的算力利用率直接影響著科研效率。筆者在參與某高校計算中心的運維工作時&#xff0c;發現以下典型問題&#xff1a; 資源黑洞現象&#xff1a;多課題組共享GPU時出現"搶…

【計算機視覺】三維重建: MVSNet:基于深度學習的多視圖立體視覺重建框架

MVSNet&#xff1a;基于深度學習的多視圖立體視覺重建框架 技術架構與核心算法1. 算法流程2. 關鍵創新 環境配置與實戰指南硬件要求安裝步驟數據準備&#xff08;DTU數據集&#xff09; 實戰流程1. 模型訓練2. 深度圖推斷3. 點云生成 常見問題與解決方案1. CUDA內存不足2. 特征…

智能家居的OneNet云平臺

一、聲明 該項目只需要創建一個產品&#xff0c;然后這個產品里面包含幾個設備&#xff0c;而不是直接創建幾個產品 注意&#xff1a;傳輸數據使用到了不同的power&#xff0c;還有一定要手機先聯網才能使用云平臺 二、OneNet云平臺創建 &#xff08;1&#xff09;Temperatur…

aidermacs開源程序使用 Aider 在 Emacs 中進行 AI 配對編程

一、軟件介紹 文末提供程序和源碼下載 Aidermacs 通過集成 Aider&#xff08;最強大的開源 AI 配對編程工具之一&#xff09;為 Emacs 帶來了 AI 驅動的開發。如果您缺少 Cursor&#xff0c;但更喜歡生活在 Emacs 中&#xff0c;Aidermacs 提供了類似的 AI 功能&#xff0c;同…

加密算法(一)-對稱加密(DES、AES、3DES、Blowfish、Twofish)一篇了解所有主流對稱加密,輕松上手使用。

一、對稱加密算法 對稱加密算法采用相同的密鑰來進行加密和解密操作。其優點是加密和解密速度快&#xff0c;不過密鑰的管理和分發存在一定的安全風險。 1.1、DES(已不推薦使用) 這是早期的對稱加密算法&#xff0c;密鑰長度為 56 位。但由于密鑰長度較短&#xff0c;如今已不…

深度優先VS廣度優先:算法選擇的核心邏輯與實戰指南

摘要 深度優先搜索&#xff08;DFS&#xff09;與廣度優先搜索&#xff08;BFS&#xff09;是圖結構遍歷與路徑分析的基礎算法&#xff0c;也是最常見的搜索框架&#xff0c;在路徑規劃、社交網絡分析、游戲AI等領域均有廣泛應用。本文從算法思想、數據結構選擇、時空復雜度和…

2025深圳杯、東三省數學建模B題數模AI全網專業性第一

為什么選擇使用我的數模AI&#xff1f; 1.輕松輔導學生 2.小白也能翻身碾壓大佬 3.突破知識壁壘&#xff0c;縮短與大佬的差距&#xff0c;打破不公平的教學資源&#xff0c;扭轉差距 4.輔助商業服務&#xff0c;成本低 5.大模型本身有一定隨機性&#xff0c;所以也不用擔心…

使用MGeo模型高精度實現文本中地址識別

一、功能與安裝 1、模型地址 模型是阿里開發的門址高精度識別模型。 https://modelscope.cn/models/iic/mgeo_geographic_elements_tagging_chinese_base/summary 注意&#xff1a;不能自己安裝包&#xff0c;沒法解決依賴問題&#xff0c;直接按照官方要求安裝下面的包&am…

【Vue】Vue與UI框架(Element Plus、Ant Design Vue、Vant)

個人主頁&#xff1a;Guiat 歸屬專欄&#xff1a;Vue 文章目錄 1. Vue UI 框架概述1.1 主流Vue UI框架簡介1.2 選擇UI框架的考慮因素 2. Element Plus詳解2.1 Element Plus基礎使用2.1.1 安裝與引入2.1.2 基礎組件示例 2.2 Element Plus主題定制2.3 Element Plus的優缺點分析 3…

MLPerf基準測試工具鏈定制開發指南:構建領域特異性評估指標的實踐方法

引言&#xff1a;基準測試的領域適配困局 MLPerf作為機器學習性能評估的"黃金標準"&#xff0c;其通用基準集在實際科研中常面臨?領域適配鴻溝?&#xff1a;醫療影像任務的Dice系數缺失、NLP場景的困惑度指標偏差等問題普遍存在。本文通過逆向工程MLPerf v3.1工具…

好看的個人主頁HTML源碼分享

源碼介紹 好看的個人主頁HTML源碼分享&#xff0c;源碼由HTMLCSSJS組成&#xff0c;記事本打開源碼文件可以進行內容文字之類的修改&#xff0c;雙擊html文件可以本地運行效果 效果預覽 源碼獲取 好看的個人主頁HTML源碼分享

mac word接入deepseek

網上大多使用Windows版word來接入deepseek&#xff0c;vba文件引入mac后&#xff0c;因底層工具不同&#xff0c;難以直接運行&#xff0c;例如CreateObject("MSXML2.XMLHTTP")無法創建&#xff0c;為此寫了一版新的vba&#xff0c;基于mac底層工具來實現。 vba文件點…

React Native 入門 jsx tsx 基礎語法

React Native 入門 jsx 基礎語法 JSX 介紹 JSX (JavaScript XML) 是一種 JavaScript 的語法擴展&#xff0c;允許你在 JavaScript 文件中編寫類似 HTML 的代碼。它是 React 和 React Native 應用程序中用來描述 UI 的主要方式。 JSX 的特點 JSX 看起來像 HTML&#xff0c;但…

HDLBIT-程序(Procedures)

始終塊(組合)【Always blocks(combinational)】 答案: Always blocks (clocked) 答案&#xff1a; module top_module(input clk,input a,input b,output wire out_assign,output reg out_always_comb,output reg out_always_ff );assign out_assigna^b;always(*)beginout_a…

值此五一勞動節來臨之際,

值此五一勞動節來臨之際&#xff0c;謹向全體員工致以節日的問候與誠摯的感謝&#xff01;正是你們的敬業與奮斗&#xff0c;成就了今天的成績。愿大家節日愉快&#xff0c;闔家幸福&#xff0c;身體健康&#xff01; #北京先智先行科技有限公司 #先知AI #節日快樂