如何无需点击屏幕实时获取像素值?实现相机画面实时取像素
解决方案
一、修复现有代码的错误
你当前的代码存在明显的颜色通道获取错误:G、B通道都误用了Color.red(pixel),正确代码如下:
sl.setDrawingCacheEnabled(true); sl.buildDrawingCache(true); bitmap = sl.getDrawingCache(); int pixel = bitmap.getPixel((int) 39, (int) 31); int r = Color.red(pixel); int g = Color.green(pixel); // 修正为green方法 int b = Color.blue(pixel); // 修正为blue方法 cl.setText("R("+r+")\nG("+g+")\nB("+b+")"); Log.d("Color Detection: ","R("+r+") "+"G("+g+") "+"B("+b+")"+Tracker.labelString.length());
二、实现无需点击的实时View像素获取
使用DrawingCache无法做到真正的实时更新,推荐通过定时任务结合资源回收机制来周期性获取像素:
实现代码
private Handler handler = new Handler(Looper.getMainLooper()); private Runnable pixelCaptureTask = new Runnable() { @Override public void run() { if (sl != null && sl.isShown()) { sl.setDrawingCacheEnabled(true); sl.buildDrawingCache(true); Bitmap cacheBitmap = sl.getDrawingCache(); if (cacheBitmap != null) { int pixel = cacheBitmap.getPixel(39, 31); int r = Color.red(pixel); int g = Color.green(pixel); int b = Color.blue(pixel); cl.setText(String.format("R(%d)\nG(%d)\nB(%d)", r, g, b)); cacheBitmap.recycle(); // 释放缓存避免内存泄漏 } sl.setDrawingCacheEnabled(false); } handler.postDelayed(this, 16); // 约60帧/秒,接近实时更新 } }; // 在页面恢复时启动任务 @Override protected void onResume() { super.onResume(); handler.post(pixelCaptureTask); } // 在页面暂停时停止任务 @Override protected void onPause() { super.onPause(); handler.removeCallbacks(pixelCaptureTask); }
注意事项
- 频繁创建绘制缓存可能引发内存问题,务必在使用后禁用缓存并回收Bitmap。
- 若View内容变化频繁,可监听
ViewTreeObserver.OnDrawListener,在View绘制完成后立即获取像素。
三、从相机画面实时获取像素值
要实现类似你提供的示例中的相机实时取色功能,推荐使用CameraX(Android Jetpack组件,兼容性更强):
步骤1:添加依赖
在build.gradle的dependencies块中加入:
def camerax_version = "1.3.0" implementation "androidx.camera:camera-core:$camerax_version" implementation "androidx.camera:camera-camera2:$camerax_version" implementation "androidx.camera:camera-lifecycle:$camerax_version" implementation "androidx.camera:camera-view:$camerax_version"
步骤2:布局添加预览组件
<androidx.camera.view.PreviewView android:id="@+id/previewView" android:layout_width="match_parent" android:layout_height="match_parent"/> <TextView android:id="@+id/colorInfo" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="#CC000000" android:textColor="#FFFFFF" android:padding="8dp" android:layout_gravity="bottom|start"/>
步骤3:实现帧分析逻辑
private PreviewView previewView; private TextView colorInfo; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_camera); previewView = findViewById(R.id.previewView); colorInfo = findViewById(R.id.colorInfo); // 启动相机 startCamera(); } private void startCamera() { // 配置预览用例 Preview preview = new Preview.Builder().build(); preview.setSurfaceProvider(previewView.getSurfaceProvider()); // 配置实时帧分析用例 ImageAnalysis imageAnalysis = new ImageAnalysis.Builder() .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST) // 只处理最新帧 .setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888) .build(); imageAnalysis.setAnalyzer(Executors.newSingleThreadExecutor(), image -> { // 获取帧像素数据 ImageProxy.PlaneProxy plane = image.getPlanes()[0]; ByteBuffer buffer = plane.getBuffer(); byte[] data = new byte[buffer.remaining()]; buffer.get(data); // 转换为Bitmap Bitmap frameBitmap = Bitmap.createBitmap(image.getWidth(), image.getHeight(), Bitmap.Config.ARGB_8888); frameBitmap.copyPixelsFromBuffer(ByteBuffer.wrap(data)); // 获取画面中心像素(可替换为你需要的坐标) int targetX = image.getWidth() / 2; int targetY = image.getHeight() / 2; int pixel = frameBitmap.getPixel(targetX, targetY); int r = Color.red(pixel); int g = Color.green(pixel); int b = Color.blue(pixel); // 回到主线程更新UI runOnUiThread(() -> { colorInfo.setText(String.format("R:%d\nG:%d\nB:%d", r, g, b)); }); // 必须关闭ImageProxy,否则会阻塞后续帧 image.close(); frameBitmap.recycle(); }); // 绑定相机与页面生命周期 CameraX.bindToLifecycle(this, preview, imageAnalysis); }
关键说明
- 需提前申请相机权限(
android.permission.CAMERA),并在运行时请求用户授权。 - 相机帧尺寸与预览显示尺寸可能存在差异,需根据预览组件的缩放比例调整目标像素坐标。
内容的提问来源于stack exchange,提问作者Peter
相关产品推荐
相关产品推荐

