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); } }
关键修改点说明
- 文本拆分与布局:将文件名和地址分成两行显示,减少横向空间占用,同时固定到右上角位置
- 背景框优化:根据两行文本+logo的总尺寸计算背景框大小,避免冗余空间
- logo集成:添加logo绘制逻辑,支持从资源加载并自动定位到文本右侧,保持垂直居中
- 参数调整:适度调整字体大小、内边距和背景透明度,平衡可读性与空间占用
- 内存优化:及时释放Mat和Bitmap资源,避免内存泄漏
内容的提问来源于stack exchange,提问作者Nicolas Lefevre
相关产品推荐
相关产品推荐

