文章目录

  • 通过计算方差判断图像是否模糊
    • 所需依赖
    • 思路描述
    • 实现前的准备
      • 模板
        • 模板子类
      • 接口
      • 工具类
        • OpenCvUtil
        • BmpUtil
        • CameraUtil
    • 布局文件
      • activity_blur_detect_page.xml 界面
      • dialog_blur.xml 对话框
    • 实现
    • 效果
    • 后续修改
      • 2021.10.20 - 使用匿名内部对象

通过计算方差判断图像是否模糊

所需依赖

  1. 图像加载库:Glide

在gradle.properties 文件中添加

implementation 'com.github.bumptech.glide:glide:4.12.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
  1. OpenCV

    下载opencv的安卓sdk并导入。

    注意,Android Studio升级Artic Fox 2020 3.1 之后从Import Module导入会有些问题,需要手动将sdk拖入项目中。

    参考:https://stackoverflow.com/questions/68649524/opencv-android-studio-module-importing-issue

思路描述

  1. 打开相机拍照;

  2. 拍照结束后计算图像方差;

  3. 根据预先设定的阈值判断图像是清晰还是模糊;

  4. 使用对话框显示判断结果。

实现前的准备

​ 异步调用opencv的方法很多,由于前不久尝试过使用模板实现图像质量检测的demo,所以这里也沿用之前写的模板方法。

模板

​ 模板的重点在于,使用顶层的抽象类固定化方法的执行顺序,使得继承相同模板的对象具有相似的内部函数执行逻辑。

​ 即,首先检查传入的图像是否有效,在执行模板子类、通过接口自定义的方法。

public abstract class DetectionTemplate {protected Bitmap srcBitmap = null;/*** 模板方法*/public final void detecting(IConstract.ICommon doAfter){if (doCheckValid()){System.out.println("开始检测");doDetect();doAfter.onDoSomething();}else{System.out.println("未开始检测");}// 钩子方法hook();}/*** 钩子方法:* 一个钩子方法由抽象类声明并实现,而子类会加以扩展。* 通常抽象类给出的实现是一个空实现,作为方法的默认实现。*/protected void hook(){}/*** 基本方法留给子类实现:* 在检测前执行, 验证参数是否正确*/protected abstract boolean doCheckValid();/*** 基本方法留给子类实现:* 在检测后执行*/
//    protected abstract void doAfterDetecting();protected abstract void doDetect();}

模板子类

/*** 图像模糊度检测*/
public class BlurDetect extends DetectionTemplate{private static final String TAG = "BlurDetect";public double sqDev = 0.0;public String strBlurDescribe = "";public BlurDetect(final Bitmap bitmap){this.srcBitmap = bitmap;}@Overrideprotected boolean doCheckValid() {return srcBitmap != null;}@Overrideprotected void doDetect() {// 获取标准差sqDev = OpenCvUtil.getSquareDeviation(srcBitmap);// 保留两位小数sqDev = NumberUtil.reserveDecimal2(sqDev);sqDev = (int)(sqDev*100)/100.0;strBlurDescribe = "模糊度: " + sqDev;Log.d(TAG, "计算结束: "+strBlurDescribe);}
}

接口

接口不是必要的,但是将自定义的接口注入模板中可以使逻辑更清晰。

/*** 接口汇总*/
public interface IConstract {/*** 通用接口*/interface ICommon{void onDetected();}
}

工具类

OpenCvUtil

/*** 自定义Opencv工具类* 包含:* Mat与Bitmap相互转换* 获取方差和标准差* 根据阈值判断模糊度*/
public class OpenCvUtil {private static final String TAG = "OpenCvUtil";// 模糊度阈值private static final int BLUR_THRESHOLD500 = 500;private static final int BLUR_THRESHOLD300 = 300;private static final int BLUR_THRESHOLD50 = 50;private static final int BLUR_THRESHOLD15 = 15;/*** Mat 转Bitmap* @param mat* @return*/public static Bitmap matToBitmap(Mat mat){Bitmap result = null;if (mat != null){result = Bitmap.createBitmap(mat.cols(), mat.rows(), Bitmap.Config.RGB_565);if (result != null){Utils.matToBitmap(mat, result);}}return result;}/*** Bitmap 转 Mat* @param bitmap* @return Mat*/public static Mat bitmapToMat(Bitmap bitmap){Mat result = null;Bitmap bmp32 = bitmap.copy(Bitmap.Config.RGB_565, true);result = new Mat(bitmap.getHeight(), bitmap.getWidth(), CvType.CV_8UC2, new Scalar(0));Utils.bitmapToMat(bmp32, result);return result;}/*** 计算图像标准差* @param bitmap* @return*/public static double getStandardDeviation(Bitmap bitmap){double result = 0.0;if (bitmap != null){result = getStdDev(bitmap);}return result;}/*** 计算图像方差* @param bitmap* @return*/public static double getSquareDeviation(Bitmap bitmap){double result = 0.0;if (bitmap != null){result = getStdDev(bitmap);}return result * result;}/*** 输入标准差,判断图像是否清晰* @param st* @param tv* @param context*/public static void judgeBlurByStdDev(final double st, final TextView tv,final Context context){judgeBlurBySquDev(st*st, tv, context);}/*** 通过方差判断* @param sq* @param tv* @param context*/public static void judgeBlurBySquDev(final double sq, final TextView tv,final Context context){tv.post(new Runnable() {@Overridepublic void run() {StringBuilder sb = new StringBuilder("模糊度: ");double tempSt = sq;// 标准差 -> 方差
//                double tempSt = st * st;sb.append(tempSt).append("\t");// 颜色可以自行设置if (tempSt > BLUR_THRESHOLD500){sb.append("清晰");tv.setTextColor(context.getColor(R.color.colorGreen));}else if(tempSt > BLUR_THRESHOLD300){sb.append("不清晰");tv.setTextColor(context.getColor(R.color.indianred));}else if(tempSt > BLUR_THRESHOLD50){sb.append("很不清晰 ");tv.setTextColor(context.getColor(R.color.indianred));}else if (tempSt > BLUR_THRESHOLD15){sb.append("非常不清晰 ");tv.setTextColor(context.getColor(R.color.colorYellow));}else{sb.append("完全看不清了 ");tv.setTextColor(context.getColor(R.color.red));}Log.d(TAG, "run: "+sb);tv.setText(sb);}});}/*** 获取模糊位图* @param srcBitmap* @return*/public static Bitmap getBlurBitmap(final Bitmap srcBitmap){Mat srcImage = bitmapToMat(srcBitmap);Mat blurImage = new Mat();blur(srcImage, blurImage, new Size(3, 3));return matToBitmap(blurImage);}// region tool/*** 获取标准差* @param bitmap* @return double 标准差*/private static double getStdDev(Bitmap bitmap) {Mat matSrc = bitmapToMat(bitmap);Mat mat = new Mat();int channel = matSrc.channels();System.out.println("getStdDev: channel = " + channel);//  1表示图像是灰度图if (channel != 1){cvtColor(matSrc, mat, COLOR_BGR2GRAY);}else{mat = matSrc;}Mat lap = new Mat();Laplacian(mat, lap, CV_64F);MatOfDouble s = new MatOfDouble();meanStdDev(lap, new MatOfDouble(), s);double st = s.get(0, 0)[0];System.out.println( "getStdDev: st = " + st);
//        Log.d(TAG, "getStdDev: s.get(0,0)[0] = "+s.get(0,0)[0]);return st;}// endregion
}

BmpUtil

/*** 自定义位图工具* 包含:* 从ImageView获取位图* 加载位图*/
public class BmpUtil {/**** @param imageView 图像控件* @return Bitmap*/public static Bitmap getBitmapFromImageView(ImageView imageView){Bitmap result = null;imageView.setDrawingCacheEnabled(true);result = Bitmap.createBitmap(imageView.getDrawingCache());imageView.setDrawingCacheEnabled(false);return result;}/*** 加载位图* @param uri* @param imageView*/public static void loadBitmap(final Uri uri, final ImageView imageView) {if (null == uri) {return;}Glide.with(imageView).load(uri).fitCenter().placeholder(R.drawable.ic_launcher_foreground).into(imageView);}/*** 加载位图* @param bitmap* @param imageView*/public static void loadBitmap(final Bitmap bitmap, final ImageView imageView) {if (null == bitmap) {return;}Glide.with(imageView).load(bitmap).fitCenter().placeholder(R.drawable.ic_launcher_foreground).into(imageView);}
}

CameraUtil

相机权限申请参考官方文档。

拍照 | Android 开发者 | Android Developers (google.cn)中提到:

请注意,startActivityForResult() 方法受调用 resolveActivity()(返回可处理 Intent 的第一个 Activity 组件)的条件保护。执行此检查非常重要,因为如果您使用任何应用都无法处理的 Intent 调用 startActivityForResult(),您的应用就会崩溃。所以只要结果不是 Null,就可以放心使用 Intent。

真机上可以正常运行,但是在模拟器上,这个返回值却总是为null导致相机无法打开。

为了解决这个问题,可以再加一个条件。

CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
String[] cameraIds = cameraManager.getCameraIdList();
if (cameraIds.length > 0) {//摄像头存在if (cameraIds[0] != null || cameraIds[1] != null) {isCamera = true;}
}

检查手机是否有摄像头,当 isCameratrue时同样跳转到拍照界面。

/*** 相机帮助类*/
public class CameraUtil {private static final String TAG = "CameraUtil";public static final int INT_OPEN_CAMERA = 1001;// 检查是否有摄像头private static boolean isCamera = false;/*** 打开相机* @param from*/@SuppressLint("QueryPermissionsNeeded")public static void openCamera(Activity from){if (!isCamera){try {CameraManager cameraManager = (CameraManager) from.getSystemService(Context.CAMERA_SERVICE);String[] cameraIds = cameraManager.getCameraIdList();if (cameraIds.length > 0) {//摄像头存在if (cameraIds[0] != null || cameraIds[1] != null) {isCamera = true;}}} catch (IllegalStateException | CameraAccessException e) {e.printStackTrace();}}Intent intentCamera = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);if (intentCamera.resolveActivity(from.getPackageManager()) != null || isCamera) {from.startActivityForResult(intentCamera, INT_OPEN_CAMERA);} else {Log.d(TAG, "onClick: 打开失败");}}
}

布局文件

字体、颜色、背景图片之类的资源文件可以自行修改。

activity_blur_detect_page.xml 界面

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"><androidx.coordinatorlayout.widget.CoordinatorLayoutandroid:id="@+id/cd_container"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:background="@drawable/app_background11"><androidx.core.widget.NestedScrollViewandroid:layout_width="match_parent"android:layout_height="match_parent"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintTop_toTopOf="parent"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><!--                <View-->
<!--                    android:layout_width="match_parent"-->
<!--                    android:layout_height="2dp"-->
<!--                    android:background="@drawable/divider"/>--><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><LinearLayoutandroid:id="@+id/ll_nowImage"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@drawable/round_lieaner_layout"><TextViewandroid:layout_width="wrap_content"android:layout_height="match_parent"android:gravity="center"android:text="选择图像:"android:textSize="@dimen/popup_item"android:lines="1"android:textColor="@color/black"/><Spinnerandroid:id="@+id/sp_imageSelector"android:layout_width="match_parent"android:layout_height="match_parent"/></LinearLayout></LinearLayout><LinearLayoutandroid:id="@+id/ll_image"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical">><ImageButtonandroid:id="@+id/ib_imageShow"android:layout_width="250dp"android:layout_height="250dp"android:layout_gravity="center_horizontal"android:layout_marginTop="7dp"android:scaleType="fitCenter"android:background="@color/translate"android:src="@drawable/drill_image_01"/><LinearLayoutandroid:layout_width="match_parent"android:layout_height="90dp"android:orientation="horizontal"android:gravity="center"android:layout_marginTop="5dp"android:layout_gravity="center"><LinearLayoutandroid:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:orientation="vertical"><TextViewandroid:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1"android:text="@string/bottomDeepthUnit"android:textSize="15sp"android:textColor="@color/white"android:gravity="center|bottom"/><TextViewandroid:id="@+id/tv_bottomDeepth"android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1"android:textSize="15sp"android:textColor="@color/white"android:gravity="center"/></LinearLayout><LinearLayoutandroid:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:orientation="vertical"><TextViewandroid:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1"android:text="@string/layerNumber"android:textSize="15sp"android:textColor="@color/white"android:gravity="center|bottom"/><TextViewandroid:id="@+id/tv_layer"android:layout_width="match_parent"android:layout_weight="1"android:layout_height="0dp"android:textSize="15sp"android:textColor="@color/white"android:gravity="center"/></LinearLayout><LinearLayoutandroid:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:orientation="vertical"><TextViewandroid:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1"android:text="@string/horizontalSizeUnit"android:textSize="15sp"android:textColor="@color/white"android:gravity="center|bottom"/><TextViewandroid:id="@+id/tv_sizeHorizontal"android:layout_width="match_parent"android:layout_weight="1"android:layout_height="0dp"android:textSize="15sp"android:textColor="@color/white"android:gravity="center"/></LinearLayout></LinearLayout></LinearLayout></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><TextViewandroid:id="@+id/tv_reminder"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="打开相机,拍摄第X箱"android:textSize="20sp"android:textColor="@color/white"android:visibility="invisible"android:gravity="center_horizontal"/><Buttonandroid:id="@+id/btn_openCamera"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginLeft="15dp"android:layout_marginTop="20dp"android:layout_marginRight="15dp"android:text="拍照"android:textSize="25sp"android:background="@drawable/round_btn_normal"/><Buttonandroid:id="@+id/btn_phone_camera"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginLeft="15dp"android:layout_marginTop="20dp"android:layout_marginRight="15dp"android:text="打开手机相机"android:textSize="25sp"android:onClick="openPhoneCamera"android:background="@drawable/round_btn_normal"android:visibility="gone"/><Buttonandroid:id="@+id/btn_back"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginLeft="15dp"android:layout_marginTop="20dp"android:layout_marginRight="15dp"android:text="返回"android:textSize="25sp"android:background="@drawable/round_btn_normal"/></LinearLayout></LinearLayout></androidx.core.widget.NestedScrollView></androidx.coordinatorlayout.widget.CoordinatorLayout></layout>

dialog_blur.xml 对话框

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="wrap_content"android:layout_height="wrap_content"><TextViewandroid:id="@+id/tv_head"android:layout_width="match_parent"android:layout_height="wrap_content"android:textSize="@dimen/text_common_content"android:text="检测结果仅作参考"android:textColor="@color/black"android:gravity="center"android:layout_gravity="center"/><TextViewandroid:id="@+id/tv_blur"android:layout_width="match_parent"android:layout_height="45dp"android:textSize="@dimen/text_common_btn"android:background="@color/translate"/></LinearLayout>

实现

/** author: hgx* time:    2021/10/19 10:23* describe: 拍照后检测照片是否模糊的demo*/
public class BlurDetectPageActivity extends AppCompatActivity {private static final String TAG = "BlurDetectPageActivity";ActivityBlurDetectPageBinding binding;private Mat imageMat;private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {@Overridepublic void onManagerConnected(int status) {switch (status) {case LoaderCallbackInterface.SUCCESS: {Log.i("OpenCV", "OpenCV loaded successfully");imageMat = new Mat();}break;default: {super.onManagerConnected(status);}break;}}};@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);binding = DataBindingUtil.setContentView(this, R.layout.activity_blur_detect_page);setBtnListener();}private void setBtnListener() {// 拍照binding.btnOpenCamera.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {CameraUtil.openCamera(BlurDetectPageActivity.this);}});}@Overrideprotected void onResume() {super.onResume();if (!OpenCVLoader.initDebug()) {Log.d("OpenCV", "Internal OpenCV library not found. Using OpenCV Manager for initialization");OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_0_0, this, mLoaderCallback);} else {Log.d("OpenCV", "OpenCV library found inside package. Using it!");mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);}}@Overrideprotected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {super.onActivityResult(requestCode, resultCode, data);Log.d(TAG, "onActivityResult: requestCode = " + requestCode);Log.d(TAG, "onActivityResult: resultCode = " + resultCode);if (resultCode == RESULT_OK) {if (requestCode == CameraUtil.INT_OPEN_CAMERA && data != null) {Bundle extras = data.getExtras();Bitmap bmpCaptured = (Bitmap) extras.get("data");// 加载位图BmpUtil.loadBitmap(bmpCaptured, binding.ibImageShow);// 检测模糊度detectBlur(bmpCaptured);}}}// 检测模糊度-方差private void detectBlur(Bitmap srcBmp) {// 模糊度检测子对象BlurDetect blurDetect = new BlurDetect(srcBmp);// 耗时操作在子线程中执行,避免ANR(Application Not Responding)new Thread(new Runnable() {@Overridepublic void run() {// 开始执行检测逻辑blurDetect.detecting(new IConstract.ICommon() {// 重载onDetected 方法,检测结束后执行@Overridepublic void onDetected() {// 在UI线程中更新控件runOnUiThread(new Runnable() {@Overridepublic void run() {double sqaDev = blurDetect.sqDev;String strDes = blurDetect.strBlurDescribe;Log.d(TAG, "run: sq = " + sqaDev);Log.d(TAG, "run: des = " + strDes);// 声明弹窗控件LayoutInflater inflater = getLayoutInflater();View view = inflater.inflate(R.layout.activity_dialog, null);// 根据方差判断图像是否清晰OpenCvUtil.judgeBlurBySquDev(sqaDev, (TextView)view.findViewById(R.id.tv_describe), getApplicationContext());// 定义弹窗AlertDialog alertDialog2 = new AlertDialog.Builder(BlurDetectPageActivity.this).setView(view).setPositiveButton("保存", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {Log.d(TAG, "onClick: 开始保存");}}).setNegativeButton("取消", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {Log.d(TAG, "onClick: 取消保存");}}).create();alertDialog2.show();}});}});}}).start();}
}

效果


后续修改

2021.10.20 - 使用匿名内部对象

模糊度检测的实现代码中

 // 检测模糊度-方差private void detectBlur(Bitmap srcBmp) {// 模糊度检测子对象BlurDetect blurDetect = new BlurDetect(srcBmp);// 耗时操作在子线程中执行,避免ANR(Application Not Responding)new Thread(new Runnable() {@Overridepublic void run() {// 开始执行检测逻辑blurDetect.detecting(new IConstract.ICommon() {// 重载onDetected 方法,检测结束后执行@Overridepublic void onDetected() {// 在UI线程中更新控件runOnUiThread(new Runnable() {@Overridepublic void run() {double sqaDev = blurDetect.sqDev;String strDes = blurDetect.strBlurDescribe;Log.d(TAG, "run: sq = " + sqaDev);Log.d(TAG, "run: des = " + strDes);// ......

blurDetectdetecting()方法中调用blurDetect的成员变量的显得比较傻气,为了试代码更加优雅,可以自定义一个匿名内部对象用来保存检测的结果。

  • 首先定义一个简单的类
/*
* author: hgx
* time:    2021/10/20 11:29
* describe: 图像检测结束后返回的对象
*/
public class DetectResult {public double resultNumber;public String describe;public DetectResult(double squareDeviation, String describe){this.resultNumber = squareDeviation;this.describe = describe;}
}
  • 再修改接口,在接口中传入这个这个类
    /*** 通用接口*/interface ICommon{void onDetected(DetectResult detectResult);}
  • 修改模板类
    主要修改了抽象方法deDetect()的返回值
public abstract class DetectionTemplate {protected Bitmap srcBitmap = null;/*** 模板方法*/public final void detecting(IConstract.ICommon doAfter){if (doCheckValid()){System.out.println("开始检测");// 传入检测结果(内部参数)doAfter.onDetected(doDetect());}else{System.out.println("未开始检测");}// 钩子方法hook();}/*** 钩子方法:* 一个钩子方法由抽象类声明并实现,而子类会加以扩展。* 通常抽象类给出的实现是一个空实现,作为方法的默认实现。*/protected void hook(){}/*** 基本方法留给子类实现:* 在检测前执行, 验证参数是否正确*/protected abstract boolean doCheckValid();// 返回检测结果protected abstract DetectResult doDetect();}
  • 修改实现子类
    主要移除了两个公有成员变量
/*
* author: hgx
* time:    2021/10/20 11:51
* describe: 图像模糊度检测
*/
public class BlurDetect extends DetectionTemplate{private static final String TAG = "BlurDetect";public BlurDetect(final Bitmap bitmap){this.srcBitmap = bitmap;}@Overrideprotected boolean doCheckValid() {return srcBitmap != null;}@Overrideprotected DetectResult doDetect() {// 获取方差double sqDev = OpenCvUtil.getSquareDeviation(srcBitmap);// 保留两位小数sqDev = NumberUtil.reserveDecimal2(sqDev);// 描述信息String strBlurDescribe = "检测结果: " + sqDev;Log.d(TAG, "计算结束: "+ strBlurDescribe);return new DetectResult(sqDev, strBlurDescribe);}
}
  • 最后是实现部分
        // 模糊度检测子对象BlurDetect blurDetect = new BlurDetect(srcBmp);// 耗时操作在子线程中执行,避免ANR(Application Not Responding)new Thread(new Runnable() {@Overridepublic void run() {// 开始执行检测逻辑blurDetect.detecting(detectResult -> {// 在UI线程中更新控件runOnUiThread(new Runnable() {@Overridepublic void run() {double sqaDev = detectResult.resultNumber;String strDes = detectResult.describe;Log.d(TAG, "run: sq = " + sqaDev);Log.d(TAG, "run: des = " + strDes);

这样子检测得到的方差和描述信息就对外隐藏了,detectResult只能在匿名函数detectResult -> {}中使用。

Android-拍照后使用OpenCV进行图像模糊度检测相关推荐

  1. android代码查找图像,Android平台上利用opencv进行图像的边沿检测

    原标题:Android平台上利用opencv进行图像的边沿检测 近开始接触opencv for Android,从网上down了图像的边沿检测的代码. 测试图片: 在Android2.3.1模拟器上跑 ...

  2. OpenCV中图像轮廓检测

    OpenCV中图像轮廓检测 通过之前的Canny方法可以得到图像的边界,但是我们无法得到边界的数学信息.所以就有了今天的图像轮廓检测. 在OpenCV中图像轮廓检测的API: findContours ...

  3. Android 拍照后图片的旋转,合并,兼容性 相机开发

    在看这篇文章之前,我建议先看相机开发基础 针对这个功能需要做自定义相机,根据Camera相机类和SurfaceView类来实现自定义图形预览拍照功能. 但在实现过程中出现几个难点: 1.如何将自己产品 ...

  4. 基于OpenCV的图像形状检测(含源码)

    导读 本文给大家分享一个用OpenCV传统方法实现形状检测的小案例. 背景介绍 实例来源:https://github.com/akshaybhatia10/ComputerVision-Projec ...

  5. Android测量图像中物体大小,android – 如何使用OpenCV从图像中检测(计数)头发?

    我使用OpenCV函数cvtColor,Canny和HoughLinesP尝试下面的代码,但在某些情况下无法获得准确的结果或无法工作. private boolean opencvProcessCou ...

  6. 利用opencv对图像和检测框做任意角度的旋转

    一.钢筋比赛中的数据扩充  #coding:utf-8 #数据集扩增 import cv2 import math import numpy as np import xml.etree.Elemen ...

  7. python+opencv 实现图像人脸检测及视频中的人脸检测

    执着于理想,纯粹于当下. 文章目录 一.数据和知识准备 1. 下载HAAR与LBP数据 2. opencv相关知识 二.python+opencv实现人脸检测 1. 图像单人脸检测 2. 图像多人脸检 ...

  8. opencv:图像轮廓检测-细胞轮廓

    对于下面的图像,进行细胞(有彩色的都是细胞)的轮廓识别,要求分割尽可能准确,轮廓是封闭的曲线. 个人的思路: 第一:通过opencv读取图片: 第二:对原图进行灰度化处理,简化矩阵,提高处理速度: 第 ...

  9. java断行_使用Java opencv连接图像中检测到的皱纹的断行

    我正在制作一个程序来检测从高分辨率相机拍摄的图像中的皱纹 . 目前该项目正处于起步阶段 . 到目前为止,我已执行了以下步骤: 转换为灰度并对比图像 . 使用高斯模糊去除噪音 . 应用自适应阈值来检测皱 ...

最新文章

  1. 宏使用 Tricks
  2. 20170623_oracle基础知识_常见问题
  3. 单载波调制和OFDM调制比较
  4. “docker exec“ requires at least 2 arguments. See ‘docker exec --help‘.
  5. Java多线程(二)之Atomic:原子变量与原子类
  6. 如何用EasyRecovery找回已经删除的图片?
  7. BG.Hive - part3
  8. KVM虚拟化技术(一)之环境部署
  9. android 2.2 sdk 下载地址,Android SDK 2.2 离线安装
  10. ndk命令行编译so库
  11. P2P技术详解(一):NAT详解——详细原理、P2P简介(转)
  12. Microsoft Office 历史版本
  13. 风控每日一问:互联网金融产品如何利用大数据做风控?
  14. Jeff Dean长文展望:2021年后,机器学习领域的五大潜力趋势!
  15. 2D平台类游戏开发教程(翻译)
  16. 如何针对数据中心进行安全疏散和消防应急管理
  17. c语言定义max和命令,C语言#define定义函数
  18. oracle 查询语句索引建议
  19. php环信发送消息,环信即时通讯 —— 消息、会话
  20. 打印log4j日志 : 超过一定大小新建日志文件 每天新建一个日志文件

热门文章

  1. **00后“砖家”开课了!今天的课题是: 什么是SD NAND? 是不是就是“传说中”的贴片式TF卡、贴片式闪存卡呢? S
  2. 行业新宠——虚拟带库
  3. 国内优秀前端 CDN,Google Fonts 国内镜像
  4. [日推荐]『法里法律咨询』没钱也能有个私人专业法律顾问,免费的
  5. Android 辅助面试题一
  6. 于殿泓 图像检测与处理技术_二手图像检测与处理技术 于殿泓 计算机 西安电子科大学出版社...
  7. 服务器系统盘一般设置多大,云服务器系统盘需要多大
  8. 基于SSH开发的旅行社管理系统
  9. 大学计算机英语 总结报告,大学英语期末总结
  10. 脑机接口科普0006——为什么要搞脑机接口