输入一个整数,要求不管输入什么,程序运行时,输入整数n都不会崩溃

作者简介:贾志凯,Testin崩溃分析项目研发工程师,负责客户端SDK相关技术研发工作。5年移动互联网开发经验,曾任职于中科院、Symantec、Opera,对移动App的测试、分析有较深入的研究。
Android系统碎片化造成应用程序崩溃严重,在模拟器上运行良好的程序安装到某款手机上说不定就会出现崩溃的现象。而且,往往都是程序发布之后在用户端出现了崩溃现象。所以,如何及时捕获并收集Android平台的崩溃就显得愈发重要。目前,市面上已经有第三方SDK可以帮助开发者完成这一功能,本文将跟大家分享一下这些崩溃分析SDK的实现原理。常见的Android崩溃有两类,一类是Java Exception异常,一类是Native Signal异常。我们将围绕这两类异常进行。对于很多基于Unity、Cocos平台的游戏,还会有C#、JavaScript、Lua等的异常,这里不做讨论。Java代码的崩溃机制及实现Android应用程序的开发是基于Java语言的,所以首先来分析第一类Android崩溃Java Exception。Exception的分类及捕获Java的异常可以分为两类:Checked Exception和UnChecked Exception。所有RuntimeException类及其子类的实例被称为Runt ime异常,即UnChecked Exception,不是RuntimeException类及其子类的异常实例则被称为Checked Exception。Checked异常又称为编译时异常,即在编译阶段被处理的异常。编译器会强制程序处理所有的Checked异常,也就是用try…catch显式的捕获并处理,因为Java认为这类异常都是可以被处理(修复)的。在Java API文档中,方法说明时,都会添加是否throw某个exception,这个exception就是Checked异常。如果没有try…catch这个异常,则编译出错,错误提示类似于“Unhandled
exception type xxxxx”。该类异常捕获的流程是:执行try块中的代码出现异常,系统会自动生成一个异常对象,并将该异常对象提交给Java运行环境,这个就是异常抛出(throw)阶段;
当Java运行环境收到异常对象时,会寻找最近的能够处理该异常对象的catch块,找到之后把该异常对象交给catch块处理,这个就是异常捕获(catch)阶段。
Checked异常一般是不引起Android App Crash的,注意是“一般”,这里之所以介绍,有两个原因:形成系统的了解,更好地对比理解UnCheckedException;
对于一些Checked Exception,虽然我们在程序里面已经捕获并处理了,但是如果能同时将该异常收集并发送到后台,将有助于提升App的健壮性。比如修改代码逻辑回避该异常,或者捕获后采用更好的方法去处理该异常。至于应该收集哪些Checked Exception,则取决于App的业务逻辑和开发者的经验了。
UnChecked异常又称为运行时异常,即Runtime-Exception,最常见的莫过于NullPointerException。UnChecked异常发生时,由于没有相应的try…catch处理该异常对象,所以Java运行环境将会终止,程序将退出,也就是我们所说的Crash。当然,你可能会说,那我们把这些异常也try…catch住不就行了。理论上确实是可以的,但有两点会导致这种方案不可行:无法将所有的代码都加上try…catch,这样对代码的效率和可读性将是毁灭性的;
UnChecked异常通常都是较为严重的异常,或者说已经破坏了运行环境的。比如内存地址,即使我们try…catch住了,也不能明确知道如何处理该异常,才能保证程序接下来的运行是正确的。
没有try…catch住的异常,即Uncaught异常,都会导致应用程序崩溃。那么面对崩溃,我们是否可以做些什么呢?比如程序退出前,弹出个性化对话框,而不是默认的强制关闭对话框,或者弹出一个提示框安慰一下用户,甚至重启应用程序等。其实Java提供了一个接口给我们,可以完成这些,这就是UncaughtExceptionHandler,该接口含有一个纯虚函数:public abstract void uncaughtException (Thread thread, Throwableex)。Uncaught异常发生时会终止线程,此时,系统便会通知UncaughtExceptionHandler,告诉它被终止的线程以及对应的异常,然后便会调用uncaughtException函数。如果该handler没有被显式设置,则会调用对应线程组的默认handler。如果我们要捕获该异常,必须实现我们自己的handler,并通过以下函数进行设置:public static void setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler handler)实现自定义的handler,只需要继承UncaughtExceptionHandler该接口,并实现uncaughtException方法即可。static class MyCrashHandler implements UncaughtExceptionHandler{
public void uncaughtException(Thread thread, final Throwable throwable) {
}在任何线程中,都可以通过setDefaultUncaughtExceptionHandler来设置handler,但在Android应用程序中,全局的Application和Activity、Service都同属于UI主线程,线程名称默认为“main”。所以,在Application中应该为UI主线程添加UncaughtExceptionHandler,这样整个程序中的Activity、Service中出现的UncaughtException事件都可以被处理。如果多次调用setDefaultUncaughtExceptionHandler设置handler,以最后一次为准。这也就是为什么多个抓崩溃的SDK同时使用,总会有一些SDK工作不正常。某些情况下,用户会既想利用第三方SDK收集崩溃,又想根据崩溃类型做出业务相关的处理。此时有两种方案:SDK提供了一个接口,允许用户传递自己handler给SDK。当执行uncaughtException的时候,SDK只负责采集崩溃信息,之后便调用用户的handler来处理崩溃了。这儿其实类似于多了一层setDefaultUncaughtExceptionHandler,只是不能和标准库用同样的名称,因为会覆盖。
用户先通过setDefaultUncaughtExceptionHandler设置自己的handler,然后SDK再次通过setDefaultUncaughtExceptionHandler设自handler前,先保存之前的handler,在SDK handler逻辑处理完成之后,再调用之前的handler处理该异常。
static class MyCrashHandler implements UncaughtExceptionHandler {
private UncaughtExceptionHandler originalH
private MyCrashHandler(Context context) {
originalHandler = Thread.getDefaultUncaughtExceptionHandler();
public void uncaughtException(Thread thread, final Throwable throwable) {
if (originalHandler != null) {
originalHandler.uncaughtException(thread, throwable);
}获取Exception崩溃堆栈捕获Exception之后,我们还需要知道崩溃堆栈的信息,这样有助于我们分析崩溃的原因,查找代码的Bug。异常对象的printStackTrace方法用于打印异常的堆栈信息,根据printStackTrace方法的输出结果,我们可以找到异常的源头,并跟踪到异常一路触发的过程。public static String getStackTraceInfo(final Throwable throwable) {
String trace = "";
Writer writer = new StringWriter();
PrintWriter pw = new PrintWriter(writer);
throwable.printStackTrace(pw);
trace = writer.toString();
pw.close();
} catch (Exception e) {
return "";
}Native代码的崩溃机制及实现Android平台除了使用Java语言开发以外,还提供了对C/C++的支持。对于一些高CPU消耗的应用程序,Java语言很难满足对性能的要求,这时就需要使用C/C++进行开发,比如游戏引擎、信号处理等。但是Native代码只能开发动态链接库(so),然后Java通过JNI来调用so库。Native崩溃分析与捕获C++也可以通过try…catch去处理一些异常,但如果出现了Uncaught异常,so库就会引起崩溃。此时肯定无法通过Java的Uncaught-ExceptionHandler来处理,那么我们应该如何捕获Native代码的崩溃呢?熟悉Linux开发的人都知道,so库一般通过gcc/g++编译,崩溃时会产生信号异常。Android底层是Linux系统,所以so库崩溃时也会产生信号异常。那么如果我们能够捕获信号异常,就相当于捕获了Android Native崩溃。信号其实是一种软件层面的中断机制,当程序出现错误,比如除零、非法内存访问时,便会产生信号事件。那么进程如何获知并响应该事件呢?Linux的进程是由内核管理的,内核会接收信号,并将其放入到相应的进程信号队列里面。当进程由于系统调用、中断或异常而进入内核态以后,从内核态回到用户态之前会检测信号队列,并查找到相应的信号处理函数。内核会为进程分配默认的信号处理函数,如果你想要对某个信号进行特殊处理,则需要注册相应的信号处理函数(如图1所示)。图1
信号检测与处理流程(原图出自《Linux内核源代码情景分析》)进程对信号异常的响应可以归结为以下几类:忽略信号:对信号不做任何处理,除了SIGKILL及SIGSTOP以外(超级用户杀掉进程时产生),其他都可以忽略;
捕获信号:注册信号处理函数,当信号发生时,执行相应的处理函数;
默认处理:执行内核分配的默认信号处理函数,大多数我们遇到的信号异常,默认处理是终止程序并生成core文件。
对Native代码的崩溃,可以通过调用sigaction()注册信号处理函数来完成。#include &signal.h&
int sigaction(int signum,const struct sigaction *act,struct sigaction *oldact));signum:代表信号编码,可以是除SIGKILL及SIGSTOP外的任何一个特定有效的信号,如果为这两个信号定义自己的处理函数,将导致信号安装错误。
act:指向结构体sigaction的一个实例的指针,该实例指定了对特定信号的处理,如果设置为空,进程会执行默认处理。
oldact:和参数act类似,只不过保存的是原来对相应信号的处理,也可设置为NULL。
sigaction函数用于改变进程接收到特定信号后的行为。如果把第二、第三个参数都设为NULL,那么该函数可用于检查信号的有效性。结构体sigaction包含了对特定信号的处理、信号所传递的信息、信号处理函数执行过程中应屏蔽掉哪些函数等等。struct sigaction {
(*sa_handler)(int);
(*sa_sigaction)(int, siginfo_t *, void *);
(*sa_restorer)(void);
}在一些体系上,sa_handler和sa_sigaction共用一个联合体(union),所以不要同时指定两个字段的值。sa_handler: 指定对signum信号的处理函数,可以是SIG_DFL默认行为,SIG_IGN忽略接送到的信号,或者一个信号处理函数指针。这个函数只有信号编码一个参数。
sa_sigaction: 当sa_flags中存在SA_SIGINFO标志时,sa_sigaction将作为signum信号的处理函数。
sa_mask:指定信号处理函数执行的过程中应被阻塞的信号。
sa_flags:指定一系列用于修改信号处理过程行为的标志,由0个或多个标志通过or运算组合而成,比如SA_RESETHAND,SA_ONSTACK | SA_SIGINFO。
sa_restorer: 已经废弃,不再使用。
各参数的详细使用说明,请参考相关资料。基于上面的分析,下面给出Native代码崩溃(即信号异常)捕获的代码片段,让大家有一个更直观的认识。const int handledSignals[] = {
SIGSEGV, SIGABRT, SIGFPE, SIGILL, SIGBUS
const int handledSignalsNum = sizeof(handledSignals) / sizeof(handledSignals[0]);
struct sigaction old_handlers[handledSignalsNum];
int nativeCrashHandler_onLoad(JNIEnv *env) {
memset(&handler, 0, sizeof(sigaction));
handler.sa_sigaction = my_
handler.sa_flags = SA_RESETHAND;
for (int i = 0; i & handledSignalsN ++i) {
sigaction(handledSignals[i], &handler, &old_handlers[i]);
}当Android应用程序加载so库的时候,调用nativeCrashHandler_onLoad会为SIGSEGV、SIGABRT、SIGFPE、SIGILL、SIGBUS通过sigaction注册信号处理函数my_sigaction。当发生Native崩溃并且发生前面几个信号异常时,就会调用my_sigaction完成信号处理。notifyNativeCrash
= (*env)-&GetMethodID(env, cls,
"notifyNativeCrash", "()V");
void my_sigaction(int signal, siginfo_t *info, void *reserved) {
// Here catch the native crash
}获取Native崩溃堆栈Android没有提供像throwable.printStackTrace一样的接口去获取Native崩溃后堆栈信息,所以我们需要自己想办法实现。这里有两种思路可以考虑。利用LogCat日志
在本地调试代码时,我们经常通过查看LogCat日志来分析解决问题。对于发布的应用,在代码中执行命令“logcat -d -v threadtime”也能达到同样的效果,只不过是获取到了用户手机的logcat。当Native崩溃时,Android系统同样会输出崩溃堆栈到LogCat,那么拿到了LogCat信息也就拿到了Native的崩溃堆栈。Process process = Runtime.getRuntime().exec(new String[]{"logcat","-d","-v","threadtime"});
String logTxt = getSysLogInfo(process.getInputStream());在my_sigaction捕获到异常信号后,通知Java层代码,在Java层启动新的进程,并在新的进程中完成上面的操作。这里注意一定要在新的进程中完成,因为原有的进程马上就会结束。网络上有一些对应这种思路的代码,但是在很多手机上都无法获得Native的崩溃堆栈。原因是对崩溃堆栈产生了破坏,使得相关信息并没有输出到logcat中。研究一下Android backtrace的底层实现以及Google Breakpad的源码,会帮助你解决这个问题。Google Breakpad
Linux提供了Core Dump机制,即操作系统会把程序崩溃时的内存内容dump出来,写入一个叫做core的文件里面。Google Breakpad作为跨平台的崩溃转储和分析模块(支持Windows、OS X、Linux、iOS和Android等),便是通过类似的MiniDump机制来获取崩溃堆栈的。通过Google Breakpad捕获信号异常,并将堆栈信息写入你指定的本地MiniDump文件中。下次启动应用程序的时候,便可以读取该MiniDump文件进行相应的操作,比如上传到后台服务器。当然,也可以修改Google Breakpad的源码,不写MiniDump文件,而是通过dumpCallback直接获得堆栈信息,并将相关信息通知到Java层代码,做相应的处理。Google Breakpad是权威的捕获Native崩溃的方法,相关的使用方法可以查看官网文档。由于它跨平台,代码体量较大,所以建议大家裁剪源码,只保留Android相关的功能,保持自己APK的小巧。视频观看地址:
责任编辑:唐小引(),邮箱:
本文为《程序员》原创文章,未经允许不得转载,订阅2016年《程序员》请点击:。
如何利用 release 版本的 backtrace 来定位 android NDK 程序的崩溃位置
我们知道 android NDK 程序在崩溃时会生成一个 tombstone 的 backtrace (也可利用 ADB logcat 抓取),从这个 backtrace 中我们可以了解是哪个函数引发...
没有更多推荐了,环境, XP_sp3, VC6
一个函数,里面用了std::string, char [], 调了一个DLL里的函数, 在结尾处return时崩溃,
崩溃原因是堆栈什么什么的, 忘了抓图
堆栈显示崩溃的位置在STLPORT的DLL里面, 看了一下和STLPORT有关的只有string, 使用没问题, 析构应该不会出问题,
然后注销了所有和string相关的代码,改用char [], 发现仍然崩溃, 不过这次是是在调DLL函数的时候
查看DLL代码,发现有个给DLL传入了一个char[], 被DLL写越界了, 导致崩溃.
错误处理之函数返回值OR异常处理
1、错误处理的方法有哪些?
2、使用函数返回值还是抛出异常?
3、PHP 原框架下的异常处理机制是怎样的?
4、PHP Yii框架下的错误处理方案是怎样的?有什么参考意义?错误处理的方...
std::bad_alloc异常一般是在new的时候因为内存不足而引起的 但是数组的越界也会导致在越界代码后进行new,ifstream,ofstream等操作抛出异常 比如如下代码
int *p ...
用C++的new操作符,分配内存,什么时候会失败?【转】Effective C++ 中文第二版 50个有效改善程序设计效率的办法条款7:预先准备好内存不够的情况operator new在无法完成内存分...
//分配内存
a= new int[bigBigNum];
catch(std::bad_alloc)
//异常处理
用C++的new操作符,分配内存,什么时候会失败?【转】
Effective C++ 中文第二版 50个有效改善程序设计效率的办法
条款7:预先准备好内存不够的情况
operator new在无...
久别重逢是说,自从在教科书上见过它一面之后,这才是第二次碰面。也就是说,在这些年的编程经历中,从来没有遇到过吧——至少在我印象中是这样的。以至于我都开始怀疑在“平常的”程序中,它是否真正存在了。内存分...
mian()函数和return的用法讲解
1、main()函数
通常而言,main函数定义一般常见有以下两种:
int main (){
return 整型。
老式用 void main(){ ...
没有更多推荐了,最近通过使用opencv做标志牌检测时,涉及到了opencv库中findContours函数的调用,在对该函数使用时出现了程序崩溃的问题,花了两天的时间才解决的该问题。
下面先对findContour函数进行简单的介绍,再次介绍一下碰到findcontours导致程序崩溃时,网络上出现的一些的解决方案,最后介绍一下我自己碰到的该问题时的解决方案。
首先,在这里先简单的对findContours函数进行简单的介绍一下吧。
findContours函数,这个函数的原型为:
void findContours(InputOutputArray image, OutputArrayOfArrays contours, OutputArray hierar-
chy, int mode, int method, Point offset=Point())
第一个参数:输入图像image必须为一个2值单通道图像。
第二个参数:contours参数为检测的轮廓数组,每一个轮廓用一个point类型的vector表示。
第三个参数:hiararchy参数和轮廓个数相同,每个轮廓contours[ i ]对应4个hierarchy元素hierarchy[ i ][ 0 ] ~hierarchy[ i ][ 3 ],分别表示后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号,如果没有对应项,该值设置为负数。
第四个参数:mode表示轮廓的检索模式。有以下几种模式:
1.CV_RETR_EXTERNAL表示只检测外轮廓
2.CV_RETR_LIST检测的轮廓不建立等级关系
3.CV_RETR_CCOMP建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层。(简单的说就是检测双层轮廓)
4.CV_RETR_TREE建立一个等级树结构的轮廓。具体参考contours.c这个demo
第五个参数:method为轮廓的近似办法,主要有以下几种:
1.CV_CHAIN_APPROX_NONE存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))==1
2.CV_CHAIN_APPROX_SIMPLE压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息
3.CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似算法
第六个参数:offset表示代表轮廓点的偏移量,可以设置为任意值。对ROI图像中找出的轮廓,并要在整个图像中进行分析时,这个参数还是很有用的。一般设置为默认值point(0,0).
findContours函数的调用小示例如下:
<code class="language-vector//可以用来过滤内外轮廓 hljs cpp">vector&vector&Point&&
findContours(Dst, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE);
//注:在检测双层轮廓时,若只提取内轮廓时,可以使用以下语句对内轮廓进行筛选出来
语句如下:
if (hierarchy[i][3] & 0)
通过对该参数的判断就能将内轮廓筛选出来。
FindContours函数先介绍这么多了。现在看一下我这篇文章的重点吧。
我在程序中使用如下:
vector&Vec4i&
vector&vector&Point&&
findContours(Dst, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE);
我现在一个工程中使用该函数对单张图像进行轮廓检测,并没有出现程序崩溃问题,但是对视频中每帧图像进行轮廓检测时,在检测第三帧图像时,程序直接崩溃,将该语句屏蔽后,程序则可以正常运行并没有问题。
我的运行环境为VS2015+Opencv2.4.11
FindContours函数出现的调用异常问题如下:
错误:File: minkernel\crts\ucrt\src\appcrt\heap\debug_heap.cpp
Expression: __acrt_first_block == header
For information on how your program can cause an assertion
failure, see the Visual C++ documentation on asserts.
以下是网上一些大神给出的解决方案(然而并不能解决我的问题)
如果使用vector&vector&Point& &作为findContours的参数,在运行时会得到
Assertion failed (mtype == type0 || (CV_MAT_CN(mtype) == CV_MAT_CN(type0) && ((1 && type0) & f…
原因是标准库里有std::vector 和 Point 和findContours里要用到的vector和Point不是一回事所以,声明的时候要用cv::vector和cv::Point就可以了。
“修改了当前程序的vc运行库配置,问题解决。具体方法是:项目-属性-配置属性-C/C++-代码生成-运行库,将其改为“多线程调试(/MTd)”。”
在配置属性-&常规-&MFC的使用中,将在静态库中使用MFC改为在共享DLL中使用MFC。
将程序改为:
vector&Mat& contours(100);
findContours( BW, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE );
当一个DLL采用静态的方式链接到C运行时库时,会创建一个相对于该DLL的堆(Heap),而如果采用共享的方式链接到C运行时库的时候则使用的是应用程序的堆内存。而_CrtIsValidHeapPointer()在 DEBug模式下将确保传入的地址在本地的堆内存中。 因此就有理由相信,真有可能是静态链接的问题。所以,我立即尝试将:
项目–属性–配置属性–常规–MFC的使用– 选择在共享DLL中使用MFC ;同时,
项目–属性–配置属性–C/C++–代码生成–运行库–选择 多线程DLL(/MD)。
通过以上可以看出,网络中从来都不缺少该领域的大神,给出的方案也是非常之多,然而并不能解决我的问题。
以下是我对于我自己程序出现的问题给出的解决方案:
通过对出现的错误:__acrt_first_block == header可以大致的知道是堆内存出现的问题,堆区一般都是用来申请分配动态数组时才会使用,而申请动态数组用的最多的就是使用关键字new[]进行申请分配。而我在程序中并未使用new,哪来的堆区的使用呢,通过查找资料了解到vector可以动态分配内存,因此问题极可能就出现在这上面。通过查阅资料了解到是vector析构异常导致的问题,可以借鉴这篇文章看一下。原文部分如下:
大概是因为 dll 如果静态链接了运行时库,dll 就会拥有独立于应用程序堆(也称作local heap)的运行时堆实例。此时在 dll 外部就不能访问此 local heap,所以也就有上面所出现的异常啦。MSDN 中也有介绍:
  The _CrtIsValidHeapPointer function is used to ensure that a specific memory address is within the local heap. The local heap refers to the heap created and managed by a particular instance of the C run-time library. If a dynamic-link library (DLL) contains a static link to the run-time library, it has its own instance of the run-time heap, and therefore its own heap, independent of the application’s local heap. When _DEBUG is not defined, calls to _CrtIsValidHeapPointer are removed during preprocessing.
程序崩溃在当析构一个带有vector成员函数对象的时候,在析构vector时,会出现这个错误,大致原因是因为析构的时候找不到vector分配的空间。
一行一行查看代码发现,对象里面的points2, status等vector变量是在calcOpticalFlowPyrLK(img1, img2, points1, points2, status, similarity, window_size, level, term_criteria, lambda, 0); 函数中分配的,即opencv的dll,所以当对象进行析构的时候,因为不能访问此local heap所以会有异常崩溃。
我的解决方法:
在调用opencv的函数之前,自己进行空间的分配。
通过阅读该片文章之后,了解到vector 析构异常 opencv Assert _CrtIsValidHeapPointer,只要在调用opencv的函数之前,自己进行空间的手动分配。于是,我对程序进行部分修改,修改程序如下:
vector&Vec4i&hierarchy(10000);
vector&Mat&contours(10000);
findContours(Dst, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE);
至此,我的程序中调用findContours函数时出现的程序崩溃问题已经完美地解决。虽然这次bug调试花了两天多的时间才解决,但是,让我知道对于程序出现同类问题,网上给出的方案不一定能解决你碰到的问题,还是要学会具体问题具体分析,不能将网上的方案进行生搬硬套,这样对于你解决问题是没有任何帮助的。最重要的是对于出现问题以及对于问题的解决方案要养成记录的好习惯,这样不仅可以在网络上实现交流共享,有助于他人学习借鉴,还可以有助于我们下次碰到该类问题时,能快速的解决问题。
Opencv findContours轮廓检测返回轮廓数过多时程序崩溃问题解决
在做测试的时候,轮廓数比较少时(应该是少于170左右),程序运行正常,能够成功return 1。当检测下面这幅图时,检测到的轮廓数为232,程序运行崩溃,提示:有未经处理的异常:将一个无效参数传递给了...
MFC中使用FindContours()函数使用时导致的程序崩溃问题的解决方案
遇见这个问题头疼了半天,尝试了N中方案,然后把网上所提供的方案整理下,看看哪一种合适你的错误。
如果使用vector &作为findContours的参数,在运行时...
Opencv2函数cvfindcontours在MFC框架下程序运行失败问题
最近利用Opencv的函数cvfindcontours查找一张图片的轮廓,基本的算法在Win32平台上正常运行没有问题,结果如下:
但是很不幸的是当调试好算法之后要将这些代码,移植到M...
Opencv FindContours报错的解决方案
近期有做关于提取图像轮廓的MFC程序,opencv的findContours函数是效果挺不错的一个选择。但我的程序在编译完全没问题的情况下出现报错。报错情况如下:
1.Debug版:在析构findC...
opencv 调用findContours异常的问题
如果使用作为findContours的参数,在运行时会得到Assertion failed (mtype == type0 || (CV_MAT_CN(mtype) =...
vs+opencv中findcontours崩溃的问题
vs+opencv中findcontours崩溃的问题最近遇到了vs2010和vs2013中findcontours崩溃的问题,查了好多,在一个人的回答里找到了解决方法vector contours(...
最近在使用opencv中的FindContours函数时总是报错,开始是无效参数,查了好多资料,试了许多种方法,都解决不了问题。不过将Debug版本改为release版本,程序就顺利运行了,真是神奇....
opencv中findContours导致crash
没用到MFC,网上的方法:
1,在配置属性-&常规-&MFC的使用中,将在静态库中使用MFC改为在共享DLL中使用MFC。无效
2,多线程调试(/MTd)改为多线程DLL调试(/MDd)。无效
findContours函数导致崩溃
在程序中使用:findContours(grayImage, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(...
没有更多推荐了,

我要回帖

更多关于 编写一个程序,输入两个整数 的文章

 

随机推荐