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.mzph.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 #节日快乐