You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android+OpenCV实现拍照后右上角叠加Logo与信息的问题求助

问题描述

我想实现这样的效果:在拍摄的图片右上角显示文件信息、地址和logo。我开发了一款应用,允许用户拍照后添加文件名、地址及logo,但结果不符合预期——文本在照片上占据了过多空间。

希望能得到实现预期效果的方案,非常感谢。


当前应用输出

我的应用输出

预期效果

期望实现的效果


我当前使用的代码

图片添加文本的核心方法

public static Bitmap addTextToImage(Bitmap bitmap, String filename, String address) {
    Mat mat = new Mat();
    Utils.bitmapToMat(bitmap, mat);

    Scalar textColor = new Scalar(120,156,181); 

    int fontFace = Imgproc.FONT_HERSHEY_SIMPLEX;
    double fontScale = 0.21; 
    int thickness = 1;
    int padding = 5; 
    
    String text = filename + " Adresse: " + address;

    Size textSize = Imgproc.getTextSize(text, fontFace, fontScale, thickness, new int[1]);

    // Position du texte : en bas à droite
    Point textPosition = new Point(
            mat.cols() - textSize.width - padding,
            mat.rows() - padding
    );

    // Dessiner un rectangle semi-transparent derrière le texte
    Rect textBackground = new Rect(
            (int) (textPosition.x - padding),
            (int) (textPosition.y - textSize.height - padding),
            (int) (textSize.width + padding * 2),
            (int) (textSize.height + padding)
    );

    Scalar backgroundColor = new Scalar(255, 255, 255, 150); 
    Imgproc.rectangle(mat, textBackground.tl(), textBackground.br(), backgroundColor, Imgproc.FILLED);
    
    Imgproc.putText(mat, text, textPosition, fontFace, fontScale, textColor, thickness);

    // Convertir à nouveau Mat en Bitmap
    Bitmap resultBitmap = Bitmap.createBitmap(mat.cols(), mat.rows(), Bitmap.Config.ARGB_8888);
    Utils.matToBitmap(mat, resultBitmap);

    return resultBitmap;
}

拍照回调代码

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == Camera.REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {

        Location lastLoc = loc.getLastLoc();

        if(lastLoc == null)
        {
            return;
        }

        String filename = generateFileName();
        Bundle extras = data.getExtras();
        Bitmap imageBitmap = (Bitmap) extras.get("data");
        Bitmap finalBitmap = PhotoAnnotator.addTextToImage(imageBitmap, filename, mSelectedAddress);

        saveImageToGallery(filename, finalBitmap, lastLoc);
    }
}

解决方案

针对你的问题,我调整了代码逻辑,实现右上角布局、拆分文本为两行、添加logo,并优化了空间占用:

修改后的核心方法(支持添加logo)

public static Bitmap addTextToImage(Bitmap bitmap, String filename, String address, Bitmap logoBitmap) {
    Mat mat = new Mat();
    Utils.bitmapToMat(bitmap, mat);

    Scalar textColor = new Scalar(120, 156, 181);
    int fontFace = Imgproc.FONT_HERSHEY_SIMPLEX;
    double fontScale = 0.3; // 适度调整字体大小,平衡可读性与空间占用
    int thickness = 1;
    int padding = 8; // 统一内边距,让布局更规整

    // 1. 拆分文本为两行:文件名一行,地址一行
    String line1 = filename;
    String line2 = "Adresse: " + address;

    // 计算两行文本的尺寸
    int[] baseline = new int[1];
    Size line1Size = Imgproc.getTextSize(line1, fontFace, fontScale, thickness, baseline);
    Size line2Size = Imgproc.getTextSize(line2, fontFace, fontScale, thickness, baseline);

    // 计算文本区域的总宽度和高度
    float maxTextWidth = Math.max(line1Size.width, line2Size.width);
    float totalTextHeight = line1Size.height + line2Size.height + padding; // 两行之间的间距

    // 2. 定位到右上角:文本区域的右上角对齐图片右上角
    float startX = mat.cols() - maxTextWidth - padding - (logoBitmap != null ? logoBitmap.getWidth() + padding : 0);
    float startY = padding + line1Size.height; // 第一行文本的基线位置

    // 3. 绘制半透明背景框(覆盖两行文本+logo区域)
    float bgWidth = maxTextWidth + padding * 2 + (logoBitmap != null ? logoBitmap.getWidth() + padding : 0);
    float bgHeight = totalTextHeight + padding * 2;
    Rect bgRect = new Rect(
            (int) (mat.cols() - bgWidth),
            padding,
            mat.cols(),
            (int) (padding + bgHeight)
    );
    Scalar bgColor = new Scalar(255, 255, 255, 180); // 适度提高透明度,增强可读性
    Imgproc.rectangle(mat, bgRect.tl(), bgRect.br(), bgColor, Imgproc.FILLED);

    // 4. 绘制两行文本
    Imgproc.putText(mat, line1, new Point(startX, startY), fontFace, fontScale, textColor, thickness);
    Imgproc.putText(mat, line2, new Point(startX, startY + line2Size.height + padding), fontFace, fontScale, textColor, thickness);

    // 5. 绘制logo(右上角对齐背景框右上角,垂直居中)
    if (logoBitmap != null) {
        Mat logoMat = new Mat();
        Utils.bitmapToMat(logoBitmap, logoMat);
        // 可选:调整logo大小适配布局
        Imgproc.resize(logoMat, logoMat, new Size(logoBitmap.getWidth() * 0.8, logoBitmap.getHeight() * 0.8));
        Point logoPos = new Point(
                mat.cols() - logoMat.cols() - padding,
                bgRect.y + (bgHeight - logoMat.rows()) / 2
        );
        // 将logo绘制到原图Mat中
        logoMat.copyTo(mat.submat((int) logoPos.y, (int) logoPos.y + logoMat.rows(), (int) logoPos.x, (int) logoPos.x + logoMat.cols()));
        logoMat.release();
    }

    // 转换回Bitmap并释放资源
    Bitmap resultBitmap = Bitmap.createBitmap(mat.cols(), mat.rows(), Bitmap.Config.ARGB_8888);
    Utils.matToBitmap(mat, resultBitmap);
    mat.release();

    return resultBitmap;
}

修改拍照回调代码(传入logo)

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == Camera.REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {

        Location lastLoc = loc.getLastLoc();
        if(lastLoc == null) {
            return;
        }

        String filename = generateFileName();
        Bundle extras = data.getExtras();
        Bitmap imageBitmap = (Bitmap) extras.get("data");
        
        // 从资源加载logo(替换成你的logo资源ID)
        Bitmap logoBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.your_logo);
        
        Bitmap finalBitmap = PhotoAnnotator.addTextToImage(imageBitmap, filename, mSelectedAddress, logoBitmap);
        // 用完回收logoBitmap,避免内存泄漏
        if (logoBitmap != null && !logoBitmap.isRecycled()) {
            logoBitmap.recycle();
        }

        saveImageToGallery(filename, finalBitmap, lastLoc);
    }
}

关键修改点说明

  1. 文本拆分与布局:将文件名和地址分成两行显示,减少横向空间占用,同时固定到右上角位置
  2. 背景框优化:根据两行文本+logo的总尺寸计算背景框大小,避免冗余空间
  3. logo集成:添加logo绘制逻辑,支持从资源加载并自动定位到文本右侧,保持垂直居中
  4. 参数调整:适度调整字体大小、内边距和背景透明度,平衡可读性与空间占用
  5. 内存优化:及时释放Mat和Bitmap资源,避免内存泄漏

内容的提问来源于stack exchange,提问作者Nicolas Lefevre

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 04:42:33