同系列的文章


1. 开发环境配置--Ubuntu+Qt4+OpenCV(一)

2. 开发环境配置--Ubuntu+Qt4+OpenCV(二)

3. 开发环境配置--Ubuntu+Qt4+OpenCV(三)


最烦的就是配置各种的开发的环境,各种琐屑没有价值的东西,但是有的时候这些工作真的是必须的,没有办法。没有这些烦人的开发环境,真的干不了活。为了做仪表盘的指针识别的工作,这些还是必须的有的,下面开始。

整个的开发环境都是在Ubuntu14.04下进行的,下面主要是在Ubuntu上安装Qt开发的相关工具和OpenCV的工具。


在Ubuntu上安装Qt开发工具

1. Ubuntu下使用atp-get安装,方法如下:

sudo apt-get install qt4-dev-tools #开发包
sudo apt-get install qtcreator #IDE
sudo apt-get install qt4-doc #开发帮助文档
sudo apt-get install qt4-qtconfig #配置工具
sudo apt-get install qt4-demos #DEMO源码

根据自己的需求,选择性的安装上面个的东西,一般都装上得了。

2. 查看自己是否安装了 build-essential和g++ :

Debian下查看软件版本的命令:

# Debian下查看软件版本
$dpkg -l | grep software_name

没有安装的话,采用以下命令进行安装:

apt-get install build-essential

apt-get install g++ 

3. 设置环境变量:

sudo gedit  /etc/profile

在最后添加两行:

PATH=$PATH:qt安装目录/bin
export PATH

source一下这个profile就生效了

qt4默认安装目录是 /usr/share/qt4/bin

4. 测试一下开发包是否正确安装

这时我们只使用了qt4-dev-tools这个开发包,相当于只安装了Java的JDK开发包。这时,即使我们不使用Qt Creator这个IDE一样可以进行程序开发,类似JDK的开发包没有Eclipse一样可以开发程序。

打开Ubuntu的终端,新建一个文件夹,命名为HelloWorld,然后进入到这个目录。建立一个hello.cpp,输入内容:

#include <QApplication>
#include <QWidget> int main(int argc, char *argv[])
{
QApplication app(argc,argv);
QWidget *ww = new QWidget();
ww->resize(300,200);
ww->show();
return app.exec();
}

这就是程序的源代码,然后在HelloWorld这个目录下,执行qmake -project生成一个当前文件夹名字命名的.pro文件,代表这个工程。

所以上面的这个hello.cpp文件在qmake -project之后,就会在HelloWorld这个目录中产生一个HelloWorld.pro的工程描述文件。

然后在执行qmake命令,这样就产生了对应的Makefile文件了,这个文件就是为了编译用的文件。

再执行make命令,这时就编译结束了,就产生了.o的目标文件hello.o和可执行的文件HelloWorld。

注意可执行文件与工程名字相同,也就是目录的名字。hello.cpp产生了hello.o文件。

最后./HelloWorld执行这个可执行文件就能运行程序了。

提示:

如果在最后make命令的时候,报错,并且报出的错误是关于qt5的信息,那就是调用了系统自带的qt5,利用指令sudo apt-get remove qt5-default删除原来的qt5,然后重新再次qmake,然后在make就可以运行了。

如果删除了原来预设的qt开发包还是不能正常的运行qt4的开发包,说是没有QApplication这个包,就再打一个包补丁:sudo apt-get install libqt4-dev。

在ubuntu上安装OpenCV

1.安装依赖的软件包

OK, so the first step is to make sure that everything in the system is updated and upgraded:

在ubuntu终端中输入命令:

sudo apt-get update
sudo apt-get upgrade

Now, you need to install many dependencies, such as support for reading and writing image files, drawing on the screen, some needed tools, etc… This step is very easy, you only need to write the following command in the Terminal:

sudo apt-get install build-essential libgtk2.0-dev libjpeg-dev libtiff4-dev libjasper-dev libopenexr-dev cmake python-dev python-numpy python-tk libtbb-dev libeigen2-dev yasm libfaac-dev libopencore-amrnb-dev libopencore-amrwb-dev libtheora-dev libvorbis-dev libxvidcore-dev libx264-dev libqt4-dev libqt4-opengl-dev sphinx-common texlive-latex-extra libv4l-dev libdc1394-22-dev libavcodec-dev libavformat-dev libswscale-dev

2.安装ffmpeg(如果你用不到处理视频文件,省略这一步)

注意:不安装ffmpeg的话,很多视频文件肯能都是打不开的。

下载ffmpeg安装包,地址:http://ffmpeg.org/releases/ffmpeg-0.7-rc1.tar.gz

(1)解压:

注意两种格式对应不同的解压命令:

tar -zxvf xxx.tar.gz
tar -jxvf xxx.tar.bz2

(2)安装三步走: ./configure -> make -> sudo make install

提示:  ./configure 的参数如下,也就用下面的命令代替./configure 

./configure --enable-gpl --enable-version3 --enable-nonfree --enable-postproc --enable-libfaac --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libtheora --enable-libvorbis --enable-libxvid --enable-x11grab --enable-swscale --enable-shared

然后,make,接着sudo make install。

3.安装opencv

(1)下载opencv的源码:

我这里下载的是openCV2.4.9的源码,我试过opencv2.2和opencv2.4.10的源代码,但是都在make的过程中出现了错误,下面说出的什么错误,然后说怎么解决。

(2)解压:

把下载下来的opencv的源码代码放到一个目录中,然后解压,解压以后会得到一个相应的目录,我的目录是:

exbot@ubuntu:~/Downloads$ pwd
/home/exbot/Downloads
exbot@ubuntu:~/Downloads$ ls -l
total 7881952
-rw------- 1 exbot exbot 3848273920 Apr 25 10:32 CentOS-6.5-i386-bin-DVD1.iso
drwxr-xr-x 14 exbot exbot 4096 May 7 09:35 ffmpeg-0.7-rc1
-rw-r--r-- 1 exbot exbot 5844263 May 7 09:26 ffmpeg-0.7-rc1.tar.gz
-rw------- 1 exbot exbot 1844527800 Apr 24 23:09 linux_11gR1_database_1013.zip
-rw------- 1 exbot exbot 1285396902 Apr 24 22:29 linux_11gR2_database_1of2.zip
-rw------- 1 exbot exbot 995359177 Apr 24 22:17 linux_11gR2_database_2of2.zip
drwxrwxr-x 12 exbot exbot 4096 May 7 10:47 opencv-2.4.9
-rw-rw-r-- 1 exbot exbot 91684751 May 7 10:45 opencv-2.4.9.zip

提示:

如果opencv源码的压缩格式是.zip的话,就用unzip命令解压,如果压缩格式是.tar.bz2的话就用tar -jxvf xxx.tar.bz2命令解压。

(3)安装cmake,安装cmake的方法又很多,这里直接介绍最简单的。why cmake?自己google去

依次执行指令

sudo apt-get install cmake
sudo apt-get install cmake-gui

(4)一般来说,编译安装都是三步走(./configure  -> make -> sudo make install),但是opencv2.2是没有./configure 的,所以要用cmake处理一下opencv2.4.9的源代码。在终端输入:

cmake-gui

打开一个如下图所示的界面:

然后,在选择源文件所在的文件夹及cmake以后的文件存在何处。我在opencv解压后的文件夹中新建了一个build文件夹,所以cmake界面的source code路径填写OpenCV解压后的目录,build the binaries路径填写OpenCV目录中新建的build目录,也就是说我的opencv是安装在…../opencv2.4.9/build目录下的。

(5)依次执行configure和generate两个指令,完成之后就可以关闭cmake-gui软件了。

然后就可以在build这个目录下面cmake了,然后在sudo make install。

提示:

如果是由于安装的版本不是opencv2.4.9而发生下面的错误:

make[2]: *** [modules/core/CMakeFiles/opencv_core.dir/src/system.cpp.o] 错误 1
make[1]: *** [modules/core/CMakeFiles/opencv_core.dir/all] 错误 2
make: *** [all] 错误 2

错误的原因发生在opencv的/home/exbot/Downloads/opencv-2.4.9/modules/core/src目录下的system.cpp这个文件中的代码错误,可以把这个文件里的代码替换为下面的:

/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/ #include "precomp.hpp" #ifdef _MSC_VER
# if _MSC_VER >= 1700
# pragma warning(disable:4447) // Disable warning 'main' signature found without threading model
# endif
#endif #if defined WIN32 || defined _WIN32 || defined WINCE
#ifndef _WIN32_WINNT // This is needed for the declaration of TryEnterCriticalSection in winbase.h with Visual Studio 2005 (and older?)
#define _WIN32_WINNT 0x0400 // http://msdn.microsoft.com/en-us/library/ms686857(VS.85).aspx
#endif
#include <windows.h>
#if (_WIN32_WINNT >= 0x0602)
#include <synchapi.h>
#endif
#undef small
#undef min
#undef max
#undef abs
#include <tchar.h>
#if defined _MSC_VER
#if _MSC_VER >= 1400
#include <intrin.h>
#elif defined _M_IX86
static void __cpuid(int* cpuid_data, int)
{
__asm
{
push ebx
push edi
mov edi, cpuid_data
mov eax, 1
cpuid
mov [edi], eax
mov [edi + 4], ebx
mov [edi + 8], ecx
mov [edi + 12], edx
pop edi
pop ebx
}
}
#endif
#endif #ifdef HAVE_WINRT
#include <wrl/client.h>
#ifndef __cplusplus_winrt
#include <windows.storage.h>
#pragma comment(lib, "runtimeobject.lib")
#endif std::wstring GetTempPathWinRT()
{
#ifdef __cplusplus_winrt
return std::wstring(Windows::Storage::ApplicationData::Current->TemporaryFolder->Path->Data());
#else
Microsoft::WRL::ComPtr<ABI::Windows::Storage::IApplicationDataStatics> appdataFactory;
Microsoft::WRL::ComPtr<ABI::Windows::Storage::IApplicationData> appdataRef;
Microsoft::WRL::ComPtr<ABI::Windows::Storage::IStorageFolder> storagefolderRef;
Microsoft::WRL::ComPtr<ABI::Windows::Storage::IStorageItem> storageitemRef;
HSTRING str;
HSTRING_HEADER hstrHead;
std::wstring wstr;
if (FAILED(WindowsCreateStringReference(RuntimeClass_Windows_Storage_ApplicationData,
(UINT32)wcslen(RuntimeClass_Windows_Storage_ApplicationData), &hstrHead, &str)))
return wstr;
if (FAILED(RoGetActivationFactory(str, IID_PPV_ARGS(appdataFactory.ReleaseAndGetAddressOf()))))
return wstr;
if (FAILED(appdataFactory->get_Current(appdataRef.ReleaseAndGetAddressOf())))
return wstr;
if (FAILED(appdataRef->get_TemporaryFolder(storagefolderRef.ReleaseAndGetAddressOf())))
return wstr;
if (FAILED(storagefolderRef.As(&storageitemRef)))
return wstr;
str = NULL;
if (FAILED(storageitemRef->get_Path(&str)))
return wstr;
wstr = WindowsGetStringRawBuffer(str, NULL);
WindowsDeleteString(str);
return wstr;
#endif
} std::wstring GetTempFileNameWinRT(std::wstring prefix)
{
wchar_t guidStr[40];
GUID g;
CoCreateGuid(&g);
wchar_t* mask = L"%08x_%04x_%04x_%02x%02x_%02x%02x%02x%02x%02x%02x";
swprintf(&guidStr[0], sizeof(guidStr)/sizeof(wchar_t), mask,
g.Data1, g.Data2, g.Data3, UINT(g.Data4[0]), UINT(g.Data4[1]),
UINT(g.Data4[2]), UINT(g.Data4[3]), UINT(g.Data4[4]),
UINT(g.Data4[5]), UINT(g.Data4[6]), UINT(g.Data4[7])); return prefix + std::wstring(guidStr);
} #endif
#else
#include <pthread.h>
#include <sys/time.h>
#include <time.h> #if defined __MACH__ && defined __APPLE__
#include <mach/mach.h>
#include <mach/mach_time.h>
#endif #endif #ifdef _OPENMP
#include "omp.h"
#endif #include <stdarg.h> #if defined __linux__ || defined __APPLE__ || defined __EMSCRIPTEN__
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#if defined ANDROID
#include <sys/sysconf.h>
#else
#include <sys/sysctl.h>
#endif
#endif #ifdef ANDROID
# include <android/log.h>
#endif namespace cv
{ Exception::Exception() { code = 0; line = 0; } Exception::Exception(int _code, const string& _err, const string& _func, const string& _file, int _line)
: code(_code), err(_err), func(_func), file(_file), line(_line)
{
formatMessage();
} Exception::~Exception() throw() {} /*!
\return the error description and the context as a text string.
*/
const char* Exception::what() const throw() { return msg.c_str(); } void Exception::formatMessage()
{
if( func.size() > 0 )
msg = format("%s:%d: error: (%d) %s in function %s\n", file.c_str(), line, code, err.c_str(), func.c_str());
else
msg = format("%s:%d: error: (%d) %s\n", file.c_str(), line, code, err.c_str());
} struct HWFeatures
{
enum { MAX_FEATURE = CV_HARDWARE_MAX_FEATURE }; HWFeatures(void)
{
memset( have, 0, sizeof(have) );
x86_family = 0;
} static HWFeatures initialize(void)
{
HWFeatures f;
int cpuid_data[4] = { 0, 0, 0, 0 }; #if defined _MSC_VER && (defined _M_IX86 || defined _M_X64)
__cpuid(cpuid_data, 1);
#elif defined __GNUC__ && (defined __i386__ || defined __x86_64__)
#ifdef __x86_64__
asm __volatile__
(
"movl $1, %%eax\n\t"
"cpuid\n\t"
:[eax]"=a"(cpuid_data[0]),[ebx]"=b"(cpuid_data[1]),[ecx]"=c"(cpuid_data[2]),[edx]"=d"(cpuid_data[3])
:
: "cc"
);
#else
asm volatile
(
"pushl %%ebx\n\t"
"movl $1,%%eax\n\t"
"cpuid\n\t"
"popl %%ebx\n\t"
: "=a"(cpuid_data[0]), "=c"(cpuid_data[2]), "=d"(cpuid_data[3])
:
: "cc"
);
#endif
#endif f.x86_family = (cpuid_data[0] >> 8) & 15;
if( f.x86_family >= 6 )
{
f.have[CV_CPU_MMX] = (cpuid_data[3] & (1 << 23)) != 0;
f.have[CV_CPU_SSE] = (cpuid_data[3] & (1<<25)) != 0;
f.have[CV_CPU_SSE2] = (cpuid_data[3] & (1<<26)) != 0;
f.have[CV_CPU_SSE3] = (cpuid_data[2] & (1<<0)) != 0;
f.have[CV_CPU_SSSE3] = (cpuid_data[2] & (1<<9)) != 0;
f.have[CV_CPU_SSE4_1] = (cpuid_data[2] & (1<<19)) != 0;
f.have[CV_CPU_SSE4_2] = (cpuid_data[2] & (1<<20)) != 0;
f.have[CV_CPU_POPCNT] = (cpuid_data[2] & (1<<23)) != 0;
f.have[CV_CPU_AVX] = (((cpuid_data[2] & (1<<28)) != 0)&&((cpuid_data[2] & (1<<27)) != 0));//OS uses XSAVE_XRSTORE and CPU support AVX
} #if defined _MSC_VER && (defined _M_IX86 || defined _M_X64)
__cpuidex(cpuid_data, 7, 0);
#elif defined __GNUC__ && (defined __i386__ || defined __x86_64__)
#ifdef __x86_64__
asm __volatile__
(
"movl $7, %%eax\n\t"
"movl $0, %%ecx\n\t"
"cpuid\n\t"
:[eax]"=a"(cpuid_data[0]),[ebx]"=b"(cpuid_data[1]),[ecx]"=c"(cpuid_data[2]),[edx]"=d"(cpuid_data[3])
:
: "cc"
);
#else
// We need to preserve ebx since we are compiling PIC code.
// This means we cannot use "=b" for the 2nd output register.
asm volatile
(
"pushl %%ebx\n\t"
"movl $7,%%eax\n\t"
"movl $0,%%ecx\n\t"
"cpuid\n\t"
"movl %%ebx,%1\n\t"
"popl %%ebx\n\t"
: "=a"(cpuid_data[0]), "=r"(cpuid_data[1]), "=c"(cpuid_data[2]), "=d"(cpuid_data[3])
:
: "cc"
);
#endif
#endif if( f.x86_family >= 6 )
{
f.have[CV_CPU_AVX2] = (cpuid_data[1] & (1<<5)) != 0;
} return f;
} int x86_family;
bool have[MAX_FEATURE+1];
}; static HWFeatures featuresEnabled = HWFeatures::initialize(), featuresDisabled = HWFeatures();
static HWFeatures* currentFeatures = &featuresEnabled; bool checkHardwareSupport(int feature)
{
CV_DbgAssert( 0 <= feature && feature <= CV_HARDWARE_MAX_FEATURE );
return currentFeatures->have[feature];
} volatile bool useOptimizedFlag = true;
#ifdef HAVE_IPP
struct IPPInitializer
{
IPPInitializer(void) { ippStaticInit(); }
}; IPPInitializer ippInitializer;
#endif volatile bool USE_SSE2 = featuresEnabled.have[CV_CPU_SSE2];
volatile bool USE_SSE4_2 = featuresEnabled.have[CV_CPU_SSE4_2];
volatile bool USE_AVX = featuresEnabled.have[CV_CPU_AVX]; void setUseOptimized( bool flag )
{
useOptimizedFlag = flag;
currentFeatures = flag ? &featuresEnabled : &featuresDisabled;
USE_SSE2 = currentFeatures->have[CV_CPU_SSE2];
} bool useOptimized(void)
{
return useOptimizedFlag;
} int64 getTickCount(void)
{
#if defined WIN32 || defined _WIN32 || defined WINCE
LARGE_INTEGER counter;
QueryPerformanceCounter( &counter );
return (int64)counter.QuadPart;
#elif defined __linux || defined __linux__
struct timespec tp;
clock_gettime(CLOCK_MONOTONIC, &tp);
return (int64)tp.tv_sec*1000000000 + tp.tv_nsec;
#elif defined __MACH__ && defined __APPLE__
return (int64)mach_absolute_time();
#else
struct timeval tv;
struct timezone tz;
gettimeofday( &tv, &tz );
return (int64)tv.tv_sec*1000000 + tv.tv_usec;
#endif
} double getTickFrequency(void)
{
#if defined WIN32 || defined _WIN32 || defined WINCE
LARGE_INTEGER freq;
QueryPerformanceFrequency(&freq);
return (double)freq.QuadPart;
#elif defined __linux || defined __linux__
return 1e9;
#elif defined __MACH__ && defined __APPLE__
static double freq = 0;
if( freq == 0 )
{
mach_timebase_info_data_t sTimebaseInfo;
mach_timebase_info(&sTimebaseInfo);
freq = sTimebaseInfo.denom*1e9/sTimebaseInfo.numer;
}
return freq;
#else
return 1e6;
#endif
} #if defined __GNUC__ && (defined __i386__ || defined __x86_64__ || defined __ppc__)
#if defined(__i386__) int64 getCPUTickCount(void)
{
int64 x;
__asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
return x;
}
#elif defined(__x86_64__) int64 getCPUTickCount(void)
{
unsigned hi, lo;
__asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
return (int64)lo | ((int64)hi << 32);
} #elif defined(__ppc__) int64 getCPUTickCount(void)
{
int64 result = 0;
unsigned upper, lower, tmp;
__asm__ volatile(
"0: \n"
"\tmftbu %0 \n"
"\tmftb %1 \n"
"\tmftbu %2 \n"
"\tcmpw %2,%0 \n"
"\tbne 0b \n"
: "=r"(upper),"=r"(lower),"=r"(tmp)
);
return lower | ((int64)upper << 32);
} #else #error "RDTSC not defined" #endif #elif defined _MSC_VER && defined WIN32 && defined _M_IX86 int64 getCPUTickCount(void)
{
__asm _emit 0x0f;
__asm _emit 0x31;
} #else #ifdef HAVE_IPP
int64 getCPUTickCount(void)
{
return ippGetCpuClocks();
}
#else
int64 getCPUTickCount(void)
{
return getTickCount();
}
#endif #endif const std::string& getBuildInformation()
{
static std::string build_info =
#include "version_string.inc"
;
return build_info;
} string format( const char* fmt, ... )
{
char buf[1 << 16];
va_list args;
va_start( args, fmt );
vsprintf( buf, fmt, args );
return string(buf);
} string tempfile( const char* suffix )
{
string fname;
#ifndef HAVE_WINRT
const char *temp_dir = getenv("OPENCV_TEMP_PATH");
#endif #if defined WIN32 || defined _WIN32
#ifdef HAVE_WINRT
RoInitialize(RO_INIT_MULTITHREADED);
std::wstring temp_dir = L"";
const wchar_t* opencv_temp_dir = GetTempPathWinRT().c_str();
if (opencv_temp_dir)
temp_dir = std::wstring(opencv_temp_dir); std::wstring temp_file;
temp_file = GetTempFileNameWinRT(L"ocv");
if (temp_file.empty())
return string(); temp_file = temp_dir + std::wstring(L"\\") + temp_file;
DeleteFileW(temp_file.c_str()); char aname[MAX_PATH];
size_t copied = wcstombs(aname, temp_file.c_str(), MAX_PATH);
CV_Assert((copied != MAX_PATH) && (copied != (size_t)-1));
fname = string(aname);
RoUninitialize();
#else
char temp_dir2[MAX_PATH] = { 0 };
char temp_file[MAX_PATH] = { 0 }; if (temp_dir == 0 || temp_dir[0] == 0)
{
::GetTempPathA(sizeof(temp_dir2), temp_dir2);
temp_dir = temp_dir2;
}
if(0 == ::GetTempFileNameA(temp_dir, "ocv", 0, temp_file))
return string(); DeleteFileA(temp_file); fname = temp_file;
#endif
# else
# ifdef ANDROID
//char defaultTemplate[] = "/mnt/sdcard/__opencv_temp.XXXXXX";
char defaultTemplate[] = "/data/local/tmp/__opencv_temp.XXXXXX";
# else
char defaultTemplate[] = "/tmp/__opencv_temp.XXXXXX";
# endif if (temp_dir == 0 || temp_dir[0] == 0)
fname = defaultTemplate;
else
{
fname = temp_dir;
char ech = fname[fname.size() - 1];
if(ech != '/' && ech != '\\')
fname += "/";
fname += "__opencv_temp.XXXXXX";
} const int fd = mkstemp((char*)fname.c_str());
if (fd == -1) return string(); close(fd);
remove(fname.c_str());
# endif if (suffix)
{
if (suffix[0] != '.')
return fname + "." + suffix;
else
return fname + suffix;
}
return fname;
} static CvErrorCallback customErrorCallback = 0;
static void* customErrorCallbackData = 0;
static bool breakOnError = false; bool setBreakOnError(bool value)
{
bool prevVal = breakOnError;
breakOnError = value;
return prevVal;
} void error( const Exception& exc )
{
if (customErrorCallback != 0)
customErrorCallback(exc.code, exc.func.c_str(), exc.err.c_str(),
exc.file.c_str(), exc.line, customErrorCallbackData);
else
{
const char* errorStr = cvErrorStr(exc.code);
char buf[1 << 16]; sprintf( buf, "OpenCV Error: %s (%s) in %s, file %s, line %d",
errorStr, exc.err.c_str(), exc.func.size() > 0 ?
exc.func.c_str() : "unknown function", exc.file.c_str(), exc.line );
fprintf( stderr, "%s\n", buf );
fflush( stderr );
# ifdef __ANDROID__
__android_log_print(ANDROID_LOG_ERROR, "cv::error()", "%s", buf);
# endif
} if(breakOnError)
{
static volatile int* p = 0;
*p = 0;
} throw exc;
} CvErrorCallback
redirectError( CvErrorCallback errCallback, void* userdata, void** prevUserdata)
{
if( prevUserdata )
*prevUserdata = customErrorCallbackData; CvErrorCallback prevCallback = customErrorCallback; customErrorCallback = errCallback;
customErrorCallbackData = userdata; return prevCallback;
} } CV_IMPL int cvCheckHardwareSupport(int feature)
{
CV_DbgAssert( 0 <= feature && feature <= CV_HARDWARE_MAX_FEATURE );
return cv::currentFeatures->have[feature];
} CV_IMPL int cvUseOptimized( int flag )
{
int prevMode = cv::useOptimizedFlag;
cv::setUseOptimized( flag != 0 );
return prevMode;
} CV_IMPL int64 cvGetTickCount(void)
{
return cv::getTickCount();
} CV_IMPL double cvGetTickFrequency(void)
{
return cv::getTickFrequency()*1e-6;
} CV_IMPL CvErrorCallback
cvRedirectError( CvErrorCallback errCallback, void* userdata, void** prevUserdata)
{
return cv::redirectError(errCallback, userdata, prevUserdata);
} CV_IMPL int cvNulDevReport( int, const char*, const char*,
const char*, int, void* )
{
return 0;
} CV_IMPL int cvStdErrReport( int, const char*, const char*,
const char*, int, void* )
{
return 0;
} CV_IMPL int cvGuiBoxReport( int, const char*, const char*,
const char*, int, void* )
{
return 0;
} CV_IMPL int cvGetErrInfo( const char**, const char**, const char**, int* )
{
return 0;
} CV_IMPL const char* cvErrorStr( int status )
{
static char buf[256]; switch (status)
{
case CV_StsOk : return "No Error";
case CV_StsBackTrace : return "Backtrace";
case CV_StsError : return "Unspecified error";
case CV_StsInternal : return "Internal error";
case CV_StsNoMem : return "Insufficient memory";
case CV_StsBadArg : return "Bad argument";
case CV_StsNoConv : return "Iterations do not converge";
case CV_StsAutoTrace : return "Autotrace call";
case CV_StsBadSize : return "Incorrect size of input array";
case CV_StsNullPtr : return "Null pointer";
case CV_StsDivByZero : return "Division by zero occured";
case CV_BadStep : return "Image step is wrong";
case CV_StsInplaceNotSupported : return "Inplace operation is not supported";
case CV_StsObjectNotFound : return "Requested object was not found";
case CV_BadDepth : return "Input image depth is not supported by function";
case CV_StsUnmatchedFormats : return "Formats of input arguments do not match";
case CV_StsUnmatchedSizes : return "Sizes of input arguments do not match";
case CV_StsOutOfRange : return "One of arguments\' values is out of range";
case CV_StsUnsupportedFormat : return "Unsupported format or combination of formats";
case CV_BadCOI : return "Input COI is not supported";
case CV_BadNumChannels : return "Bad number of channels";
case CV_StsBadFlag : return "Bad flag (parameter or structure field)";
case CV_StsBadPoint : return "Bad parameter of type CvPoint";
case CV_StsBadMask : return "Bad type of mask argument";
case CV_StsParseError : return "Parsing error";
case CV_StsNotImplemented : return "The function/feature is not implemented";
case CV_StsBadMemBlock : return "Memory block has been corrupted";
case CV_StsAssert : return "Assertion failed";
case CV_GpuNotSupported : return "No GPU support";
case CV_GpuApiCallError : return "Gpu API call";
case CV_OpenGlNotSupported : return "No OpenGL support";
case CV_OpenGlApiCallError : return "OpenGL API call";
}; sprintf(buf, "Unknown %s code %d", status >= 0 ? "status":"error", status);
return buf;
} CV_IMPL int cvGetErrMode(void)
{
return 0;
} CV_IMPL int cvSetErrMode(int)
{
return 0;
} CV_IMPL int cvGetErrStatus(void)
{
return 0;
} CV_IMPL void cvSetErrStatus(int)
{
} CV_IMPL void cvError( int code, const char* func_name,
const char* err_msg,
const char* file_name, int line )
{
cv::error(cv::Exception(code, err_msg, func_name, file_name, line));
} /* function, which converts int to int */
CV_IMPL int
cvErrorFromIppStatus( int status )
{
switch (status)
{
case CV_BADSIZE_ERR: return CV_StsBadSize;
case CV_BADMEMBLOCK_ERR: return CV_StsBadMemBlock;
case CV_NULLPTR_ERR: return CV_StsNullPtr;
case CV_DIV_BY_ZERO_ERR: return CV_StsDivByZero;
case CV_BADSTEP_ERR: return CV_BadStep;
case CV_OUTOFMEM_ERR: return CV_StsNoMem;
case CV_BADARG_ERR: return CV_StsBadArg;
case CV_NOTDEFINED_ERR: return CV_StsError;
case CV_INPLACE_NOT_SUPPORTED_ERR: return CV_StsInplaceNotSupported;
case CV_NOTFOUND_ERR: return CV_StsObjectNotFound;
case CV_BADCONVERGENCE_ERR: return CV_StsNoConv;
case CV_BADDEPTH_ERR: return CV_BadDepth;
case CV_UNMATCHED_FORMATS_ERR: return CV_StsUnmatchedFormats;
case CV_UNSUPPORTED_COI_ERR: return CV_BadCOI;
case CV_UNSUPPORTED_CHANNELS_ERR: return CV_BadNumChannels;
case CV_BADFLAG_ERR: return CV_StsBadFlag;
case CV_BADRANGE_ERR: return CV_StsBadArg;
case CV_BADCOEF_ERR: return CV_StsBadArg;
case CV_BADFACTOR_ERR: return CV_StsBadArg;
case CV_BADPOINT_ERR: return CV_StsBadPoint; default:
return CV_StsError;
}
} static CvModuleInfo cxcore_info = { 0, "cxcore", CV_VERSION, 0 }; CvModuleInfo* CvModule::first = 0, *CvModule::last = 0; CvModule::CvModule( CvModuleInfo* _info )
{
cvRegisterModule( _info );
info = last;
} CvModule::~CvModule(void)
{
if( info )
{
CvModuleInfo* p = first;
for( ; p != 0 && p->next != info; p = p->next )
; if( p )
p->next = info->next; if( first == info )
first = info->next; if( last == info )
last = p; free( info );
info = 0;
}
} CV_IMPL int
cvRegisterModule( const CvModuleInfo* module )
{
CV_Assert( module != 0 && module->name != 0 && module->version != 0 ); size_t name_len = strlen(module->name);
size_t version_len = strlen(module->version); CvModuleInfo* module_copy = (CvModuleInfo*)malloc( sizeof(*module_copy) +
name_len + 1 + version_len + 1 ); *module_copy = *module;
module_copy->name = (char*)(module_copy + 1);
module_copy->version = (char*)(module_copy + 1) + name_len + 1; memcpy( (void*)module_copy->name, module->name, name_len + 1 );
memcpy( (void*)module_copy->version, module->version, version_len + 1 );
module_copy->next = 0; if( CvModule::first == 0 )
CvModule::first = module_copy;
else
CvModule::last->next = module_copy; CvModule::last = module_copy; return 0;
} CvModule cxcore_module( &cxcore_info ); CV_IMPL void
cvGetModuleInfo( const char* name, const char **version, const char **plugin_list )
{
static char joint_verinfo[1024] = "";
static char plugin_list_buf[1024] = ""; if( version )
*version = 0; if( plugin_list )
*plugin_list = 0; CvModuleInfo* module; if( version )
{
if( name )
{
size_t i, name_len = strlen(name); for( module = CvModule::first; module != 0; module = module->next )
{
if( strlen(module->name) == name_len )
{
for( i = 0; i < name_len; i++ )
{
int c0 = toupper(module->name[i]), c1 = toupper(name[i]);
if( c0 != c1 )
break;
}
if( i == name_len )
break;
}
}
if( !module )
CV_Error( CV_StsObjectNotFound, "The module is not found" ); *version = module->version;
}
else
{
char* ptr = joint_verinfo; for( module = CvModule::first; module != 0; module = module->next )
{
sprintf( ptr, "%s: %s%s", module->name, module->version, module->next ? ", " : "" );
ptr += strlen(ptr);
} *version = joint_verinfo;
}
} if( plugin_list )
*plugin_list = plugin_list_buf;
} namespace cv
{ #if defined WIN32 || defined _WIN32 || defined WINCE struct Mutex::Impl
{
Impl()
{
#if (_WIN32_WINNT >= 0x0600)
::InitializeCriticalSectionEx(&cs, 1000, 0);
#else
::InitializeCriticalSection(&cs);
#endif
refcount = 1;
}
~Impl() { DeleteCriticalSection(&cs); } void lock() { EnterCriticalSection(&cs); }
bool trylock() { return TryEnterCriticalSection(&cs) != 0; }
void unlock() { LeaveCriticalSection(&cs); } CRITICAL_SECTION cs;
int refcount;
}; #ifndef __GNUC__
int _interlockedExchangeAdd(int* addr, int delta)
{
#if defined _MSC_VER && _MSC_VER >= 1500
return (int)_InterlockedExchangeAdd((long volatile*)addr, delta);
#else
return (int)InterlockedExchangeAdd((long volatile*)addr, delta);
#endif
}
#endif // __GNUC__ #elif defined __APPLE__ #include <libkern/OSAtomic.h> struct Mutex::Impl
{
Impl() { sl = OS_SPINLOCK_INIT; refcount = 1; }
~Impl() {} void lock() { OSSpinLockLock(&sl); }
bool trylock() { return OSSpinLockTry(&sl); }
void unlock() { OSSpinLockUnlock(&sl); } OSSpinLock sl;
int refcount;
}; #elif defined __linux__ && !defined ANDROID struct Mutex::Impl
{
Impl() { pthread_spin_init(&sl, 0); refcount = 1; }
~Impl() { pthread_spin_destroy(&sl); } void lock() { pthread_spin_lock(&sl); }
bool trylock() { return pthread_spin_trylock(&sl) == 0; }
void unlock() { pthread_spin_unlock(&sl); } pthread_spinlock_t sl;
int refcount;
}; #else struct Mutex::Impl
{
Impl() { pthread_mutex_init(&sl, 0); refcount = 1; }
~Impl() { pthread_mutex_destroy(&sl); } void lock() { pthread_mutex_lock(&sl); }
bool trylock() { return pthread_mutex_trylock(&sl) == 0; }
void unlock() { pthread_mutex_unlock(&sl); } pthread_mutex_t sl;
int refcount;
}; #endif Mutex::Mutex()
{
impl = new Mutex::Impl;
} Mutex::~Mutex()
{
if( CV_XADD(&impl->refcount, -1) == 1 )
delete impl;
impl = 0;
} Mutex::Mutex(const Mutex& m)
{
impl = m.impl;
CV_XADD(&impl->refcount, 1);
} Mutex& Mutex::operator = (const Mutex& m)
{
CV_XADD(&m.impl->refcount, 1);
if( CV_XADD(&impl->refcount, -1) == 1 )
delete impl;
impl = m.impl;
return *this;
} void Mutex::lock() { impl->lock(); }
void Mutex::unlock() { impl->unlock(); }
bool Mutex::trylock() { return impl->trylock(); } //////////////////////////////// thread-local storage //////////////////////////////// class TLSStorage
{
std::vector<void*> tlsData_;
public:
TLSStorage() { tlsData_.reserve(16); }
~TLSStorage();
inline void* getData(int key) const
{
CV_DbgAssert(key >= 0);
return (key < (int)tlsData_.size()) ? tlsData_[key] : NULL;
}
inline void setData(int key, void* data)
{
CV_DbgAssert(key >= 0);
if (key >= (int)tlsData_.size())
{
tlsData_.resize(key + 1, NULL);
}
tlsData_[key] = data;
} inline static TLSStorage* get();
}; #ifdef WIN32
#ifdef _MSC_VER
#pragma warning(disable:4505) // unreferenced local function has been removed
#endif #ifdef HAVE_WINRT
// using C++11 thread attribute for local thread data
static __declspec( thread ) TLSStorage* g_tlsdata = NULL; static void deleteThreadData()
{
if (g_tlsdata)
{
delete g_tlsdata;
g_tlsdata = NULL;
}
} inline TLSStorage* TLSStorage::get()
{
if (!g_tlsdata)
{
g_tlsdata = new TLSStorage;
}
return g_tlsdata;
}
#else
#ifdef WINCE
# define TLS_OUT_OF_INDEXES ((DWORD)0xFFFFFFFF)
#endif
static DWORD tlsKey = TLS_OUT_OF_INDEXES; static void deleteThreadData()
{
if(tlsKey != TLS_OUT_OF_INDEXES)
{
delete (TLSStorage*)TlsGetValue(tlsKey);
TlsSetValue(tlsKey, NULL);
}
} inline TLSStorage* TLSStorage::get()
{
if (tlsKey == TLS_OUT_OF_INDEXES)
{
tlsKey = TlsAlloc();
CV_Assert(tlsKey != TLS_OUT_OF_INDEXES);
}
TLSStorage* d = (TLSStorage*)TlsGetValue(tlsKey);
if (!d)
{
d = new TLSStorage;
TlsSetValue(tlsKey, d);
}
return d;
}
#endif //HAVE_WINRT #if defined CVAPI_EXPORTS && defined WIN32 && !defined WINCE
#ifdef HAVE_WINRT
#pragma warning(disable:4447) // Disable warning 'main' signature found without threading model
#endif BOOL WINAPI DllMain(HINSTANCE, DWORD fdwReason, LPVOID); BOOL WINAPI DllMain(HINSTANCE, DWORD fdwReason, LPVOID)
{
if (fdwReason == DLL_THREAD_DETACH || fdwReason == DLL_PROCESS_DETACH)
{
cv::deleteThreadAllocData();
cv::deleteThreadRNGData();
cv::deleteThreadData();
}
return TRUE;
}
#endif #else
static pthread_key_t tlsKey = 0;
static pthread_once_t tlsKeyOnce = PTHREAD_ONCE_INIT; static void deleteTLSStorage(void* data)
{
delete (TLSStorage*)data;
} static void makeKey()
{
int errcode = pthread_key_create(&tlsKey, deleteTLSStorage);
CV_Assert(errcode == 0);
} inline TLSStorage* TLSStorage::get()
{
pthread_once(&tlsKeyOnce, makeKey);
TLSStorage* d = (TLSStorage*)pthread_getspecific(tlsKey);
if( !d )
{
d = new TLSStorage;
pthread_setspecific(tlsKey, d);
}
return d;
}
#endif class TLSContainerStorage
{
cv::Mutex mutex_;
std::vector<TLSDataContainer*> tlsContainers_;
public:
TLSContainerStorage() { }
~TLSContainerStorage()
{
for (size_t i = 0; i < tlsContainers_.size(); i++)
{
CV_DbgAssert(tlsContainers_[i] == NULL); // not all keys released
tlsContainers_[i] = NULL;
}
} int allocateKey(TLSDataContainer* pContainer)
{
cv::AutoLock lock(mutex_);
tlsContainers_.push_back(pContainer);
return (int)tlsContainers_.size() - 1;
}
void releaseKey(int id, TLSDataContainer* pContainer)
{
cv::AutoLock lock(mutex_);
CV_Assert(tlsContainers_[id] == pContainer);
tlsContainers_[id] = NULL;
// currently, we don't go into thread's TLSData and release data for this key
} void destroyData(int key, void* data)
{
cv::AutoLock lock(mutex_);
TLSDataContainer* k = tlsContainers_[key];
if (!k)
return;
try
{
k->deleteDataInstance(data);
}
catch (...)
{
CV_DbgAssert(k == NULL); // Debug this!
}
}
}; // This is a wrapper function that will ensure 'tlsContainerStorage' is constructed on first use.
// For more information: http://www.parashift.com/c++-faq/static-init-order-on-first-use.html
static TLSContainerStorage& getTLSContainerStorage()
{
static TLSContainerStorage *tlsContainerStorage = new TLSContainerStorage();
return *tlsContainerStorage;
} TLSDataContainer::TLSDataContainer()
: key_(-1)
{
key_ = getTLSContainerStorage().allocateKey(this);
} TLSDataContainer::~TLSDataContainer()
{
getTLSContainerStorage().releaseKey(key_, this);
key_ = -1;
} void* TLSDataContainer::getData() const
{
CV_Assert(key_ >= 0);
TLSStorage* tlsData = TLSStorage::get();
void* data = tlsData->getData(key_);
if (!data)
{
data = this->createDataInstance();
CV_DbgAssert(data != NULL);
tlsData->setData(key_, data);
}
return data;
} TLSStorage::~TLSStorage()
{
for (int i = 0; i < (int)tlsData_.size(); i++)
{
void*& data = tlsData_[i];
if (data)
{
getTLSContainerStorage().destroyData(i, data);
data = NULL;
}
}
tlsData_.clear();
} } // namespace cv /* End of file. */

这样之后在make就不会报错了。

(6)配置OpenCV,更新动态链接库

用root用户执行下面的操作

添加路径/usr/local/lib到文件/etc/ld.so.conf,然后运行命令。

终端中输入以下这行命令:

sudo gedit /etc/ld.so.conf.d/opencv.conf 

打开的文档中添加 下面这一行代码

/usr/local/lib 

保存关闭文档。紧接着,终端输入 

sudo ldconfig

使修改生效。

打开另外一个文件,终端中输入以下这行代码:

sudo gedit /etc/bash.bashrc

在该文档的最后添加以下这两行:

PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig
export PKG_CONFIG_PATH

最后,Finally, close the console and open a new one, restart the computer or logout and then login again. OpenCV will not work correctly until you do this。到这里为止Opencv的整个安装过程结束了。


利用安装好的OpenCV做一些sample

到源码的文档中找sample,执行一个脚本,进入OpenCV-2.4.9是最开始的源代码,不是cmake以后的!!同时注意下面运行的两个例子,我的用户的名字是exbot,这涉及到文件路径的问题,如果你的用户是stemon,就把路径上的exbot换成stemon。

cd Downloads/opencv-2.4.9/samples/c
chmod +x build_all.sh
./build_all.sh
然后运行下面的例子:
./facedetect --cascade="/home/exbot/Downloads/opencv-2.4.9/data/haarcascades/haarcascade_frontalface_alt.xml" --scale=1.5 lena.jpg
再来一个:
./facedetect --cascade="/home/exbot/Downloads/opencv-2.4.9/data/haarcascades/haarcascade_frontalface_alt.xml" --nested-cascade="/home/exbot/Downloads/opencv-2.4.9/data/haarcascades/haarcascade_eye.xml" --scale=1.5 lena.jpg

OpenCV安装参考链接

system.cpp错误解决链接:https://github.com/Itseez/opencv/commit/ea50be0529c248961e1b66293f8a9e4b807294a6?diff=unified

安装教程链接:http://www.samontab.com/web/2012/06/installing-opencv-2-4-1-ubuntu-12-04-lts/

中文教程:http://blog.csdn.net/moc062066/article/details/6617968

开发环境配置--Ubuntu+Qt4+OpenCV(一)的更多相关文章

  1. 开发环境配置--Ubuntu+Qt4+OpenCV(三)

    同系列文章 1. 开发环境配置--Ubuntu+Qt4+OpenCV(一) 2. 开发环境配置--Ubuntu+Qt4+OpenCV(二) 3. 开发环境配置--Ubuntu+Qt4+OpenCV(三 ...

  2. 开发环境配置--Ubuntu+Qt4+OpenCV(二)

    同系列文章 1. 开发环境配置--Ubuntu+Qt4+OpenCV(一) 2. 开发环境配置--Ubuntu+Qt4+OpenCV(二) 3. 开发环境配置--Ubuntu+Qt4+OpenCV(三 ...

  3. DELPHI10.2的LINUX数据库开发环境配置

    DELPHI10.2的LINUX数据库开发环境配置 ubuntu使用firedac访问mysql1.安装mysql-client包sudo apt-get install mysql-client m ...

  4. Ubuntu开发环境配置

    主要是: 源的更新 安装vim编辑器 远程登录xrdp相关配置 synergy symless键鼠共享配置 对新买的硬盘进行格式化和分区 vsftp环境搭建 gcc开发环境配置 qt5开发环境配置 m ...

  5. 【OpenCV入门教程之一】 安装OpenCV:OpenCV 3.0 +VS 2013 开发环境配置

    图片太多,具体过程参照: [OpenCV入门教程之一] 安装OpenCV:OpenCV 3.0.OpenCV 2.4.8.OpenCV 2.4.9 +VS 开发环境配置 说下我这边的设置: 选择deb ...

  6. Fedora和Ubuntu下安装OpenGL开发环境配置

    Fedora下OpenGl开发环境配置 开发OpenGL工程需要3个库文件和对应的头文件: libglut.so,libGLU.so,libGL.so, gl.h ,glu.h, glut.h 这些库 ...

  7. (转)OpenCV 2.4.8 +VS2010的开发环境配置

    转自:  http://blog.csdn.net/poem_qianmo/article/details/19809337 自己可能需要再进行修改 本系列文章由zhmxy555(毛星云)编写,转载请 ...

  8. 【OpenCV入门教程之一】 安装OpenCV:OpenCV 3.0、OpenCV 2.4.8、OpenCV 2.4.9 +VS 开发环境配置

    本系列文章由@浅墨_毛星云 出品,转载请注明出处.   文章链接:http://blog.csdn.net/poem_qianmo/article/details/19809337 作者:毛星云(浅墨 ...

  9. OpenCv的Java,C++开发环境配置

    1.OpenCV 下载及安装配置 opencv的下载地址:http://opencv.org/downloads.html 最新版本:opencv3.0.0 注意:支持的visual studio20 ...

随机推荐

  1. 配置文件的读取添加webconfig

    webconfig.xml的配置文件内容挺丰富的,在这篇文章里笔者只对AppSettings这个节点进行配置文件读取和添加 public class ConfigurationRef { /// &l ...

  2. (九)Android权限系统

    一.WebView请求权限实例 1.WebView获取网页访问权限的xml布局文件和MainActivity中的程序如下 <WebView android:layout_width=" ...

  3. JSP简介

    论坛 博客 微论 问答 游戏厅 天涯客 读书 更多 手机 服务 登录 注册   聚焦 民生 文学 旅游 财经 汽车 IT数码 时尚 情感 娱乐 视频 更多 北京 上海 广东 更多 天涯部落> J ...

  4. zookeeper_00:zookeeper注意事项

    需要将应用数据和协同数据独立开. 比如:网络邮箱服务的用户对自己邮箱中的内容感兴趣,但是并不关心由哪台服务器来处理特定邮箱的请求.在这个例子中,邮箱内容就是应用数据,而从邮箱到某一台邮箱服务器之间的映 ...

  5. Web页面在手机上显示过大问题

    网上抄来了,自己也备忘下:增加<meta name="viewport" content="width=device-width, initial-scale=1. ...

  6. Android 判断当前设备是否联网

    首先添加相关的权限: <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> ...

  7. MYSQL设置字段数据过长自动截断

    自动截断如下设置: windows: 修改my.ini: [mysqld] sql-mode="STRICT_TRANS_TABLES" linux: 修改/ect/mysql/m ...

  8. SQL字符型字段按数字型字段排序实现方法(转)

    由于是按字母顺序排列,所以123排在了2的前面,显然不符合我们的要求,那么怎样才能按照我们预想的数字顺序排序呢 ORDER BY `meta_value`   那么按得分排序得到的结果可能是:1101 ...

  9. PTF在PET上印刷線路的注意事項

    PTF: Polymer Thick Film (聚合厚模),維基的解釋 PET: Polyethylene terephthalate (聚乙烯對苯二甲酸酯),維基的解釋 就如同大家所知道的,相較於 ...

  10. Delphi检测网络连接状态

    有时候,我们做一些小软件就需要检测网络连接状态,比如想给你的软件加上类似QQ那样的系统消息,可是像我这样的穷人肯定是买不起服务器了,那我们只好另想办法,可以读取网页然后用浏览器显示,这个时候就需要判断 ...