Mat 简介:#####

Mat 用于管理图像在内存中的存储,在Opencv 3 中由于使用了内存自动管理机制,所以不必像最早的Opencv一样需要手动分配和释放内存空间,Mat是由两个部分组成的。一个图像数据矩阵头包括(矩阵尺寸、存储方法、存储地址等信息),另一个是指向存储图像所有像素值的矩阵空间的指针。
这样设计是由于一般图像数据都是比较大的,并且很多时候都是需要经过多个不同的函数处理,这就导致了需要在不同的函数间传递这个大数据结构,除非万不得已不会选择去传递比较大的Mat。所以Opencv设计了这种结构来完成Mat的快速传递,Mat矩阵头是一个常数值,而矩阵保存了图像所有的像素值,这部分通常会比矩阵头大几个数量级,在函数间传递参数的时候每个Mat都有自己的信息头,但是矩阵数据是共享的,也就是在传递Mat时,只复制矩阵头和指向矩阵的指针。

在Mat的实现中使用了引用计数机制,每次Mat对象的信息头被复制了,都会增加矩阵的引用次数加1;反之,当一个Mat的信息头被释放后,引用计数就会被减1;当计数被减到0时,矩阵就会被释放。

上述的方式我们可以知道这种情况下矩阵数据是共享的,任何一个函数改动都会影响到这个矩阵,但是有时候我们需要独立的矩阵空间,这时候可以使用clone和 copyTo。通过clone和copyTo创建的Mat,都有自己的矩阵,修改其中一个的矩阵不会对其他的造成影响。

Mat 属性:#####

data uchar型的指针。就是上面提到的指向矩阵数据的指针。
dims 矩阵的维度
rows 矩阵的行数
cols 矩阵的列数
size 矩阵的大小
channels 矩阵元素通道数

type
命名规则为CV_(位数)+(数据类型)+(通道数)。具体的有以下值:它表示的是每个像素的元素的存储方式
CV_8UC1 CV_8UC2 CV_8UC3 CV_8UC4
CV_8SC1 CV_8SC2 CV_8SC3 CV_8SC4 …

depth 色彩深度
depth 的类型如下所示:
CV_8U CV_8S CV_16U CV_16S CV_32S CV_32F CV_64F
elemSize
矩阵一个元素占用的字节数
elemSize1
矩阵元素一个通道占用的字节数

Mat 创建和初始化:#####
cv::Mat img(20,20,CV_8UC3,cv::Scalar(255,255,255));

上述代码创建了一个20行20列的矩阵,矩阵元素使用8位无符号char类型保存,具有3通道,每个像素的初始值是(255,255,255)黑色,这里需要注意Scalar的表示顺序为BGR
构造函数的前两个参数指定了矩阵的行和列
第三个参数指定矩阵元素的数据类型以及通道数,其指定规则如下:

img.create(20,20,CV_8UC(3));
该方法不能为矩阵设置初始值

特殊矩阵的创建:

cv::Mat e = cv::Mat::eye(20,20,CV_64F); 对角矩阵
cv::Mat z = cv::Mat::ones(20,20,CV_32F); 单位矩阵
cv::Mat o = cv::Mat::zeros(20,20,CV_8UC3); 零矩阵

小矩阵的创建:
一些如核等小矩阵的创建还可以使用如下方式:

Mat c =(Mat_<double>(3,3)<<1,0,0,0,1,0,0,0,1);
矩阵的直观表示:#####

颜色空间缩减:#####

将现有的颜色空间进行映射,以获得较少的颜色数,目的是为了加快部分算法的处理速度

矩阵的遍历:#####
#include <QCoreApplication>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>

void changeImageUsePointer(cv::Mat& sourceImage,cv::Mat& dstImage,uchar radio) {

dstImage = sourceImage.clone();
int rows = dstImage.rows;
int cols = dstImage.cols * dstImage.channels();
for(int rowindex = 0 ;rowindex < rows ;rowindex++) {
uchar *element = dstImage.ptr<uchar>(rowindex);
for(int colindex = 0; colindex < cols;colindex++) {
element[colindex] = static_cast<uchar>(element[colindex]/radio)*radio;
}
}
}

void changeImageByIterator(cv::Mat& sourceImage,cv::Mat& dstImage,uchar radio) {
dstImage = sourceImage.clone();
cv::MatIterator_<cv::Vec3b> beginIterator = dstImage.begin<cv::Vec3b>();
cv::MatIterator_<cv::Vec3b> endIterator = dstImage.end<cv::Vec3b>();
cv::MatIterator_<cv::Vec3b> iterator;
for(iterator = beginIterator ;iterator != endIterator; ++iterator) {
(*iterator)[0] = ((*iterator)[0]/radio)*radio;
(*iterator)[1] = ((*iterator)[1]/radio)*radio;
(*iterator)[2] = ((*iterator)[2]/radio)*radio;
}
}

void changeImageByLocation(cv::Mat& sourceImage,cv::Mat& dstImage,uchar radio) {
dstImage = sourceImage.clone();
int cols = dstImage.cols;
int rows = dstImage.rows;

for(int row = 0;row < rows;row++) {
for(int col = 0;col < cols;col++) {
uchar b = dstImage.at<cv::Vec3b>(row,col)[0];
dstImage.at<cv::Vec3b>(row,col)[0] = (b/radio)*radio;

uchar g = dstImage.at<cv::Vec3b>(row,col)[1];
dstImage.at<cv::Vec3b>(row,col)[1] = (g/radio)*radio;

uchar r = dstImage.at<cv::Vec3b>(row,col)[2];
dstImage.at<cv::Vec3b>(row,col)[2] = (b/radio)*radio;
}
}
}
int const PROCESS_TIME = 10;
int const COLOR_REDUCE = 10;
int main(int argc, char *argv[]) {

cv::Mat srcImage = cv::imread("/home/jimmy/QtOpenCV/image/test_access.png");
if(!srcImage.data) {
return -1;
}
cv::Mat dstImage;
dstImage.create(srcImage.rows,srcImage.cols,srcImage.type());

int64 startTime = cv::getTickCount();
for(int i = 0;i< PROCESS_TIME; i++) {
changeImageUsePointer(srcImage,dstImage,COLOR_REDUCE);
}
int64 endTime = cv::getTickCount();
qDebug("Consume Time by Pointer= %f",(endTime-startTime)/cv::getTickFrequency()/PROCESS_TIME);

startTime = cv::getTickCount();
for(int i = 0;i< PROCESS_TIME; i++) {
changeImageByIterator(srcImage,dstImage,COLOR_REDUCE);
}
endTime = cv::getTickCount();
qDebug("Consume Time by Pointer= %f",(endTime-startTime)/cv::getTickFrequency()/PROCESS_TIME);

startTime = cv::getTickCount();
for(int i = 0;i< PROCESS_TIME; i++) {
changeImageByLocation(srcImage,dstImage,COLOR_REDUCE);
}
endTime = cv::getTickCount();
qDebug("Consume Time by Pointer= %f",(endTime-startTime)/cv::getTickFrequency()/PROCESS_TIME);

cv::namedWindow("Test Access SRC");
cv::namedWindow("Test Access Dest");
cv::imshow("Test Access SRC",srcImage);
cv::imshow("Test Access Dest",dstImage);
int keycode = cv::waitKey(0);
if(keycode == 27) {
cv::destroyAllWindows();
}
}

项目目录结构:

3rdparty/ :包含第三方的库,比如视频解码用的 ffmpeg,jpg、png、tiff等图片的开源解码库。
apps/ :包含进行 haar 分类器训练的工具,
cmake/:包含生成工程项目时 cmake 的依赖文件,用于智能搜索第三方库,普通开发者不需要关心这个文件夹的内容。
data/:包含 opencv 库以及范例中用到的资源文件,haar 物体检测的分类器位于haarcascades子文件中。
doc/:包含生成文档所需的源文件以及辅助脚本。
include/:包含入口头文件。opencv 子文件夹中是 C 语言风格的API,官方将逐渐淘汰 C 风格函数,不推荐大家使用该文件夹中的头文件。opencv2 子文件中只有一个 opencv.hpp 文件,这是 cv2 以及 cv3 推荐使用的头文件。
modules/:包含核心代码,opencv 真正的代码都在这个文件夹中。
platforms/:包含交叉编译所需的工具链以及额外的代码.
samples/:样例目录。

重要的Module介绍:

androidcamera/,仅用于android平台,使得可以通过与其他平台相同的接口来控制android设备的相机。
core/,核心功能模块,定义了基本的数据结构,包括最重要的 Mat 类、XML 读写、opengl三维渲染等。
imgproc/,全称为 image processing,即图像处理。包括图像滤波、集合图像变换、直方图计算、形状描述子等。图像处理是计算机视觉的重要工具
imgcodec/,负责各种格式的图片的读写,这个模块是从以前的 highgui 中剥离的。
highgui/,高级图形界面及与 QT 框架的整合。
video/,视频分析模块。包括背景提取、光流跟踪、卡尔曼滤波等,做视频监控的读者会经常使用这个模块。
videoio/,负责视频文件的读写,也包括摄像头、Kinect 等的输入。
calib3d/,相机标定以及三维重建。相机标定用于去除相机自身缺陷导致的画面形变,还原真实的场景,确保计算的准确性。三维重建通常用在双目视觉(立体视觉),即两个标定后的摄像头观察同一个场景,通过计算两幅画面中的相关性来估算像素的深度。
features2d/,包含 2D 特征值检测的框架。包含各种特征值检测器及描述子,例如 FAST、MSER、OBRB、BRISK等。各类特征值拥有统一的算法接口,因此在不影响程序逻辑的情况下可以进行替换。
objdetect/,物体检测模块。包括haar分类器、SVM检测器及文字检测。
ml/,全称为 Machine Learning,即机器学习。包括统计模型、K最近邻、支持向量机、决策树、神经网络等经典的机器学习算法。
flann/,用于在多维空间内聚类及搜索的近似算法.
photo/,计算摄影学。包括图像修补、去噪、HDR成像、非真实感渲染等。如果读者想实现Photoshop的高级功能,那么这个模块必不可少。
stitching/,图像拼接,可用于制作全景图。
nonfree/,受专利保护的算法。包含SIFT和SURF,从功能上来说这两个算法属于features2d模块的,但由于它们都是受专利保护的,想在项目中可能需要专利方的许可。
shape/,形状匹配算法模块。用于描述形状、比较形状。
softcascade/,另一种物体检测算法,Soft Cascade 分类器。包含检测模块和训练模块。
superres/,全称为 Super Resolution,用于增强图像的分辨率。
videostab/,全称为 Video Stabilization,用于解决相机移动时拍摄的视频不够稳定的问题。
viz/,三维可视化模块。可以认为这个模块实现了一个简单的三维可视化引擎,有各种UI控件和键盘、鼠标交互方式。底层实现基于 VTK 这个第三方库。

Sample 目录例子介绍;

摘自: http://lv.xiao.yu.blog.163.com/blog/static/5419127320138191291534/

parter 1:
No1. adaptiveskindetector.cpp
利用HSV空间的色调信息的皮肤检测,背景不能有太多与肤色相似的颜色。效果不是特别好。
No2. bagofwords_classification.cpp
好大一串……目前还看不懂。
No3. bgfg_codebook.cpp
前后背景分离。开启摄像头或读取视频。
No4. bgfg_gmg.cpp
摄像头捕捉,根据运动进行前后背景分离。
No5. bgfg_segm.cpp
高斯处理视频。跟踪运动做前背景分割。BackgroundSubtractorMOG2类。
No6. blobtrack_sample.cpp
视频跟踪。跟踪视频中的运动物体,用绿色线框出。
No7. brief_match_test.cpp
利用brief描述算子匹配二维图像特征点。line118出错.???
No8. build3dmodel.cpp
建立三维模型。根据给出的检测器对原始进行建模。
No9. calibration.cpp 3calibration.cpp
相机外定标。根据自带的函数提取角点后定标,效果很不好。
No10. calibration_artificial
根据角点自动校准摄像。初始化后寻找角点再用calibrateCamera校准,有findChessboardCorners估计效果不怎么好。
No11. chamfer.cpp
图像匹配。把图像二值后在目标图像中寻找模板图像。主要调用chamerMatching函数。
No12. contours.c
轮廓查找与获取。cvFindContours一个函数搞定。
No13. convert_cascade.c
从文件中装载训练好的级联分类器或者从OpenCV中嵌入的分类器数据库中导入 然后另存为一个文件。
No14. convexhull.cpp
凸包。产生随机点后计算凸包。
No15. cout_mat.cpp
opencv中矩阵的输出。
No16. delaunay.c delaunay2.cpp
根据随机点进行Delaunay三角测量找到边,结束时计算Voronoi图表的细胞结构。
No17. demhist.cpp
直方图均衡化来调节图像的亮度和对比度,输出黑白图像。
No18. descriptor_extractor_matcher.cpp
7-8个参数。SIFT匹配。
No19. detector_descriptor_evaluation.cpp
计算检测算子。各种Dataset。
No20. detector_descriptor_matcher_evaluation.cpp
计算检测算子匹配。也是各种Dataset。
No21. dft.cpp
对图像进行离散Fourier变换。数学变换。
No22. distrans.cpp
距离变换。计算输入图像所有非零元素和其最近的零元素的距离。
No23. drawing.cpp
简单的画点、线、文字等。不解释。
No24. edge.cpp
边缘检测。通过滑动条调节阈值,利用Canny检测图像边缘后显示,很简单的一个代码。
No25. em.cpp
em聚类。
No26. fabmap_sample
fab-mat匹配。从训练数据中建立Chow-Liu树。
No27. facedetect.cpp smiledetect.cpp
人脸检测。根据已训练好的分类器对人脸图像进行检测,用不同颜色的圆形框或矩形框标记出检测出的五官。
No28. facerec_demo.cpp
人脸识别。
No29. fback.cpp fback_c.c
计算视频的光流。默认打开摄像头,有些卡,速度慢。
No30. filestorage.cpp
Mat矩阵存储,读写xml/yml文件。
No31. find_obj.cpp
有关Surf算法的示例。利用匹配在目标图像中寻找样本图像中的物体。
No32. find_obj_calonder.cpp
通过训练分类树检测目标物体。需要训练图像。
No33. find_obj_ferns.cpp
同样是目标检测。基于随机蕨丛的快速识别关键点。
No34. fitellipse.cpp
椭圆拟合,查找图像轮廓图形。findContours很有用。总体效果不理想。
No35. freak_demo.cpp
利用特征点进行图像匹配。特征点描述包括A. Alahi, R. Ortiz, and P. Vandergheynst. FREAK: FastRetina Keypoint.
No36. gencolors.cpp
输入颜色数量,产生着色条带状图像。色带宽20。
No37. generic_descriptor_match.cpp
SURF图像匹配。输入参数包括两幅图像和参数数据。
No38. houghlines.cpp houghcircles.cpp
利用Hough变换提取图像中的直线或圆。效果一般。Canny很重要。
No39. image.cpp
基本的图像和视频读取,图像加噪和平滑处理。
No40. kalman.cpp
Kalman滤波,先建立运动模型和观察模型。对绕圆周运动的一维点跟踪,算法结果显示了估计点和实际点的连线。
No41. kmeans.cpp
聚类分析。在平面上产生随机点后用K-means算法作聚类迭代,由于聚类中心也是随机产生的,可知效果很不好。
No42. laplace.cpp
也是边缘检测。由滑动条调整阈值,先对图像作滤波(高斯,均值,中值),后Laplace检测边缘。参数sigma=3时效果最好。
No43. latentsvmdetect.cpp
用latentSVM检测目标。
No44. letter_recog.cpp
演示训练各种不同的分类器,使用uci的字符库数据集。
No45. logpolar_bsm.cpp
坐标的相互转化。
No46. matcher_simple.cpp
SURF图像匹配。参数少,效果和generic_descriptor_match.cpp相似。
No47. matching_to_many_images.cpp
多幅图像的匹配。强大的SURF算法。
No48. meanshift_segmentation.cpp
meanshift图像分割。三个参数spatialRad、colorRad和maxPyrLevel可调。
No49. minarea.cpp
产生随机点后计算包含所有点的面积最小的圆和矩形。纯数学问题。
No50. morphology.c morphology2.cpp
形态学基本运算,包括开/闭运算,膨胀/腐蚀运算。
No51. motempl.c
运动跟踪。
No52. mser_sample.cpp
MSER方法区域提取图像轮廓。使用颜色距离阈值的基于MSER方法的最大稳定颜色区域检测子(MaximallyStable Colour Regions,MSCR)。
No53. mushroom.cpp
演示建立决策分类树训练 使用mushroom数据
No54. one_way_sample.cpp
基于主成分分析的特征点匹配问题。运行时间好长……
No55. opencv_version.cpp
显示opencv版本。简单的几行代码。
No56. OpenEXRimages_HighDynamicRange_Retina_toneMapping.cpp
OpenEXRimages_HighDynamicRange_Retina_toneMapping_video.cpp
不清楚。
No57. openni_capture.cpp
开放式的自然交互视频捕捉。Depth generator。
No58. pca.cpp
主成份分析算法。重建。
No59. peopledetect.cpp
HOG (Histogram-of-Oriented Gradients)行人或人体检测,使用的是hog特征和svm。
No60. phase_corr.cpp
基于相位的相关图像运动方位跟踪程序。
No61. points_classifier.cpp
点分类。鼠标点击给定点和类。
No62. polar_transform.c
线性坐标和极坐标相互转换。可以从摄像头捕捉图像。
No63. pyramid_segmentation.c
金字塔图像分割。
No64. retinaDemo.cpp
Retina特征点检测。
No65. rgbdodometry.cpp
视觉里程计算法。为了估计刚体变换,试图找到翘曲,即最大化之间连续两个RGBD的帧不同的图像尺度。
No66. segment_objects.cpp
视频跟踪分割运动中的物体。
No67. select3dobj.cpp
收集数据集对象和分割遮罩,显示了如何使用相机的校准模式。计算该单对应性校准图案上的平面。还显示grabCut分割等。
No68. simpleflow_demo.cpp
一种光流算法。
No69. squares.cpp
寻找矩形。
No70. starter_imagelist.cpp
根据图像列表文件yaml读取并显示图像。
No71. starter_video.cpp
打开视频图像选择画面保存为图片。
No72. stereo_calib.cpp
摄像机立体校准。
No73. stereo_match.cpp
立体匹配。
No74. stitching.cpp stitching_detailed.cpp
图像拼接。涉及到特征点的提取、特征点匹配、图像融合等等。Stitcher类。
No75. tvl1_optical_flow.cpp
光流法视频跟踪。
No76. tree_engine.cpp
演示使用不同的决策树 CvDTree dtree;决策树 CvBoost boost;Boosted tree classifier监督学习树
CvRTrees rtrees;随机树 CvERTrees ertrees;完全随机树。
No77. video_dmtx.cpp
视频截图。
No78. video_homography.cpp
使用features2d的快速角点检测。
No79. videostab.cpp
稳定视频。
No80. watershed
做分水岭图像分割。

parter 2:
No1. camshiftdemo.cpp
彩色目标跟踪。根据鼠标点击一个区域的色度光谱来跟踪视频目标。
No2. connected_components.cpp
连通区域。findContours+drawContours。
No3. contours2.cpp
先画一张线条图后检测轮廓。参数可调。
No4. ffilldemo.cpp
漫水填充。根据鼠标选取的点搜索图像中与之颜色相近的点,用不同颜色标注。
No5. grabcut.cpp
图像分割,鼠标选取矩形框,抠出前景,分离背景。效果还挺不错的。
No6. hybridtrackingsample.cpp
混合跟踪。调试时HybridTracker那出错了,不懂。
No7. imagelst_creator.cpp
把图像名称列表写成yaml或xml格式。
No8. inpaint.cpp
数字图像修复程序,基于纹理合成。先在图像上随便画,按”i”键后显示修复的图像。
No9. linemod.cpp
line196出错.???
No10. lkdemo.cpp
点跟踪。改进的Lucas-Kanade光流算法,检测视频运动目标。鼠标点击目标点,视频跟踪。

parter3:
No1. detection_based_tracker_sample.cpp
UNIX或ANDROID平台上使用的例子。基于检测的跟踪。

这篇文章会记录在Opencv使用过程中遇到的各种错误:

1.在pyton 中使用Opencv过程中 import cv2 会出现如下错误:

ImportError: No module named cv2

解决方法:

在 ~/.bashrc 中添加 export PYTHONPATH=/usr/local/lib/python2.7/site-packages:$PYTHONPATH

2.编译 opencv-3.1.0 过程中会出现

QtOpenGL: No such file or directory #include

需要安装如下依赖包:

sudo apt-get install libqt5opengl5 libqt5opengl5-dev

3.Qt 编写的代码运行时出现类似错误:

/usr/local/lib/libopencv_imgcodecs.so.3.1:-1: error: error adding symbols: DSO missing from command line

这种一般是链接库没有添加:
往项目的pro文件中的动态库链接部分添加报错的库:
如下所示:

INCLUDEPATH += /usr/local/include \
/usr/local/include/opencv \
/usr/local/include/opencv2

LIBS += /usr/local/lib/libopencv_highgui.so \
/usr/local/lib/libopencv_core.so \
/usr/local/lib/libopencv_imgproc.so \
/usr/local/lib/libopencv_imgcodecs.so <------ 这个库没有添加导致的,往这里添加

最近感觉有点脑子不够用,学过的东西长期不用的话很快就会忘记,趁着这段时间把之前学的东西都整理下,也算是对之前的技术做个回顾和总结。
今天介绍如何在Ubuntu下安装Open CV + Python的开发环境。opencv是一个十分强大的图像处理以及机器视觉算法库,它支持Java,C++,以及Python。
目前可以在Android可以很轻松得搭建开发环境了,这个会在后续的文章中予以介绍,之所以选择Python是因为简单,花一个下午就就可以把常用的语法给过一遍了,但是后来发现深入进去还是有的学的,后续打算以OpenCV + python作为一个专题介绍下图像处理中的一些技术。

好了,进入正题:

  1. 首先运行下如下的命令,更新下软件库

    $ sudo apt-get update
    $ sudo apt-get upgrade
  2. 安装开发必要的工具,下面的这些,比如git 如果大家的系统上已经安装好了就不用安装了

    sudo apt-get install build-essential cmake git pkg-config
  3. 为了能够加载 JPEG, PNG, TIFF这些格式的图片,需要安装这些格式的图片读写包:

sudo apt-get install libjpeg8-dev libtiff4-dev libjasper-dev libpng12-dev
  1. 图像显示的话我这里选择的是 GTK 开发库,执行如下命令安装:

    sudo apt-get install libgtk2.0-dev
  2. 为了能够处理视频流我们需要安装如下的包:

    sudo apt-get install libavcodec-dev libavformat-dev libswscale-dev libv4l-dev
  3. 下面这个不是很清楚,当时笔记上的,先装上吧:

    sudo apt-get install libatlas-base-dev gfortran

  4. 安装pip 是用于安装Python包的工具

    wget https://bootstrap.pypa.io/get-pip.py && sudo python get-pip.py 
  5. 使用上面安装的Pip 安装virtualenv,virtualenvwrapper这个有助于你创建独立的Python开发环境:

    sudo pip install virtualenv virtualenvwrapper
    export WORKON_HOME=$HOME/.virtualenvs
    source /usr/local/bin/virtualenvwrapper.sh
    source ~/.bashrc
  6. 创建一个独立的开发环境

    mkvirtualenv cv
  7. 安装Pyhon 2.7

    sudo apt-get install python2.7-dev
  8. 由于需要涉及到多维数组的运行所以需要使用pip 安装 numpy库

    pip install numpy
  9. 安装opencv 3.0

    cd ~
    git clone https://github.com/Itseez/opencv.git
    cd opencv
    git checkout 3.0.0
    cd ~
    git clone https://github.com/Itseez/opencv_contrib
    cd opencv_contrib
    git checkout 3.0.0
  10. 使用cmake编译opencv

    cd ~/opencv
    mkdir build
    cd build
    cmake -D CMAKE_BUILD_TYPE=RELEASE \
    -D CMAKE_INSTALL_PREFIX=/usr/local \
    -D INSTALL_C_EXAMPLES=ON \
    -D INSTALL_PYTHON_EXAMPLES=ON \
    -D BUILD_EXAMPLES=ON ..
    make -j4

这时候有可能会报如下错误:

/usr/bin/ld: /usr/local/lib/libavcodec.a(avpacket.o): relocation R_X86_64_32 against `.rodata.str1.1’ can not be used when making a shared object; recompile with -fPIC
/usr/local/lib/libavcodec.a: error adding symbols: Bad value
collect2: error: ld returned 1 exit status
make[2]: *** [lib/libopencv_videoio.so.3.0.0] Error 1
make[1]: *** [modules/videoio/CMakeFiles/opencv_videoio.dir/all] Error 2
make: *** [all] Error 2

这是由于你当时编译ffmpeg的时候方式不对,参考如下结合方法:

I had the same problem while compiling opencv3 alpha on Ubuntu 14.04 with FFMPEG enabled. My FFMPEG was the git version compiled with
./configure
make
sudo make install
I had to recompile FFMPEG with
./configure –enable-nonfree –enable-pic –enable-shared

That did the trick for me and after that opencv3 compiled fine.

Stackflow OpenCV make fails - “recompile with -fPIC”

在安装过程中还有可能会遇到如下错误:

/home/jimmy/opencv/modules/videoio/src/cap_ffmpeg_impl.hpp: In member function ‘bool OutputMediaStream_FFMPEG::open(const char*, int, int, double)’:
/home/jimmy/opencv/modules/videoio/src/cap_ffmpeg_impl.hpp:2150:41: warning: ignoring return value of ‘int avformat_write_header(AVFormatContext*, AVDictionary**)’, declared with attribute warn_unused_result [-Wunused-result]
avformat_write_header(oc_, NULL);
^
make[2]: *** [modules/videoio/CMakeFiles/opencv_videoio.dir/src/cap_ffmpeg.cpp.o] Error 1
make[1]: *** [modules/videoio/CMakeFiles/opencv_videoio.dir/all] Error 2
make[1]: *** Waiting for unfinished jobs….
Linking CXX shared library ../../lib/libopencv_shape.so
[ 47%] Built target opencv_shape
make: *** [all] Error 2

这是由于我在上面重装ffmpeg的时候安装的是最新的3.0版本导致部分方法不兼容,我这边ffmpeg安装回2.3版本就可以了

这时候还有可能发现在终端敲ffmpeg的时候会报如下错误:

ffmpeg: error while loading shared libraries: libavdevice.so.55: cannot open shared object file: No such file or directory

解决办法:
运行:

sudo vim /etc/ld.so.conf

在文件的最后添加

/usr/lib
/usr/local/lib

运行:

ldconfig
  1. 编好后就安装吧
sudo make install
sudo ldconfig

但是我们的cv虚拟环境是在我们的home目录下,所以要在虚拟环境下使用OpenCV,我们还得将opencv 链接到这个地方。

cd ~/.virtualenvs/cv/lib/python2.7/site-packages/
ln -s /usr/local/lib/python2.7/site-packages/cv2.so cv2.so
  1. 测试下:
$ workon cv
$ python
>>> import cv2
>>> cv2.__version__
'3.0.0'

创建Qt Console 项目:
main.cpp 代码如下:
很简单就是加载一张图片后显示出来,就和所有语言的Hello World一样

#include <QCoreApplication>
#include <QCoreApplication>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

int main(int argc,char *argv[]) {
cv::Mat image = cv::imread("/home/jimmy/games.jpg",cv::IMREAD_GRAYSCALE);
cv::imshow("Test Opencv",image);
cv::waitKey(0);
cv::destroyAllWindows();
}

在pro文件中添加如下包含关系:

INCLUDEPATH += /usr/local/include \
/usr/local/include/opencv \
/usr/local/include/opencv2

LIBS += /usr/local/lib/libopencv_highgui.so \
/usr/local/lib/libopencv_core.so \
/usr/local/lib/libopencv_imgproc.so \
/usr/local/lib/libopencv_imgcodecs.so

整个pro文件如下所示:

QT       += core
QT -= gui
TARGET = LearnOpencv
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
SOURCES += main.cpp

INCLUDEPATH += /usr/local/include \
/usr/local/include/opencv \
/usr/local/include/opencv2

LIBS += /usr/local/lib/libopencv_highgui.so \
/usr/local/lib/libopencv_core.so \
/usr/local/lib/libopencv_imgproc.so \
/usr/local/lib/libopencv_imgcodecs.so

Ctrl + R 就可以看到一个图片以灰度图的形式加载进来。

安装Opencv

Step 1: 创建目录

mkdir opencv
cd /opencv/

Step 2: 移除之前安装的 ffmpeg 和 x264
sudo apt-get -qq remove ffmpeg x264 libx264-dev
Step 3: 安装相关依赖
sudo apt-get -qq install libopencv-dev build-essential checkinstall cmake pkg-config yasm libjpeg-dev libjasper-dev libavcodec-dev libavformat-dev libswscale-dev libdc1394-22-dev libxine-dev libgstreamer0.10-dev libgstreamer-plugins-base0.10-dev libv4l-dev python-dev python-numpy libtbb-dev libqt4-dev libgtk2.0-dev libfaac-dev libmp3lame-dev libopencore-amrnb-dev libopencore-amrwb-dev libtheora-dev libvorbis-dev libxvidcore-dev x264 v4l-utils

安装ffmpeg

sudo add-apt-repository ppa:mc3man/trusty-media
sudo apt-get update
sudo apt-get install ffmpeg gstreamer0.10-ffmpeg
Step 4: 下载和解压opencv
下载opencv_contrib-master,opencv-3.1.0
对应的Github路径如下:
https://github.com/Itseez/opencv/
https://github.com/Itseez/opencv_contrib
解压opencv_contrib-master,opencv-3.1.0
其中opencv_contrib是一些为引入到主版本上的新特性,为了学习这些新特性最好也将它安装上。
cd opencv-3.1.0
Step 5: Begin Build Process

Note that this bit would take some time to complete

mkdir build
cd build
cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D WITH_TBB=ON -D BUILD_NEW_PYTHON_SUPPORT=ON -D WITH_V4L=ON -D INSTALL_C_EXAMPLES=ON -D INSTALL_PYTHON_EXAMPLES=ON -D BUILD_EXAMPLES=ON -D WITH_QT=ON -D WITH_OPENGL=ON -DOPENCV_EXTRA_MODULES_PATH=/home/jimmy/Desktop/opencv_contrib-master/modules /home/jimmy/Desktop/opencv-3.1.0 ..

这里注意的是这里的/home/jimmy/Desktop/opencv_contrib-master/modules是步骤4中下载的opencv_contrib-master下的module 目录,
/home/jimmy/Desktop/opencv-3.1.0为步骤4中下载的opencv-3.1.0目录,这个是为了安装opencv_contrib而添加的。

编译安装

make -j5
sudo make install
sudo sh -c 'echo "/usr/local/lib" > /etc/ld.so.conf.d/opencv.conf'
sudo ldconfig

重启电脑

我们应该明确一点Git是一个分布式的版本控制系统,和SVN这种集中式的版本控制相比,它有很多好处。
首先我们介绍下什么是集中式,什么是分布式版本控制系统。
在集中式版本控制系统中版本库是集中存放在一台单独的中央服务器的,在我们开始工作的时候需要先从中央服务器取得最新的版本,然后开始干活,最后再把自己的代码推送到中央服务器。

而分布式版本控制系统没有中央服务器的概念,每个人的电脑上有一个完整的版本库,因此在工作的时候,就不需要联网了。多人协作的时候就可以把各自的修改直接推送给对方,但是在实际使用分布式版本控制系统的时候,很少使用刚刚提到的那种直接推送的方式,一般分布式版本控制系统通常也有一台中央服务器,但这个服务器的作用仅仅是用来方便交换各自的修改的,没有中央服务器也一样可以工作,只是使用起来会比较不方便而已。

下面分别是SVN 和 CVN工作方式的视图(图片来自图解Git相关工作流)

Git-GitHub_CVN

Git-GitHub_CVN

上图中很明显得看出,SVN模式下要是中央服务器挂掉的话后果是十分严重的,而分布式版本控制系统,中有个Local Repository 如果中央服务器挂掉,可以使用这个代码库对其进行恢复。

下面就以一个简单的工作流展开介绍:
Git-GitHub_CVN

安装Git

配置Git

Git配置变量可能保存在如下三个地方:
/etc/gitconfig 文件:系统中对所有用户都适用的配置(若使用git config –system 时配置的是这个文件)
~/.gitconfig文件:只适用于当前用户的配置(若使用git config –global 时配置的就是这个文件)
.git/config文件:仅仅针对当前项目有效的配置。 (若使用git config 时配置的就是这个文件)

配置指令:

git config --global user.name “xiaohai.lin”
git config --global user.email xiaohai.lin.hz@tcl.com
git config –global core.editor emacs
Git config –global merge.tool vimdiff

查询配置:

git  config --list
这里可能会看到重复的名字,这说明采用了不同的配置,Git实际采用的是最后的一个。

代码仓库的创建

首先你要有个repo,repo的创建可以有两种方式一种是从无到有,一种是通过Clone 一份现有的代码作为开发的起点。

  • 从无到有开始创建

    mkdir myrepo 创建一个本地的目录
    cd myrepo 进入到本地repo
    git init 初始化repo

    这时候当前的目录转换成一个Git仓库。它在当前的目录下增加了一个.git文件夹,所有的提交将会都记录到这个文件夹下。

  • Clone 一份现有的代码作为开发的起点

    git clone /path/to/repository (本地仓库的克隆)
    git clone username@host:/path/to/repository (通过SSH)
    git clone https:/path/to/repository.git (通过https)
  • Fork Github上的某个项目作为开发起点

    fork操作就相当于复制一份目标库(包括文件,提交历史,issues,和其余一些东西),通过fork你就可以自由得对项目进行修改而不用担心你的修改会影响到原始的项目。fork后仓库在你自己的GitHub帐号下。

    下面就以fork butterknife这个项目为例来介绍如何fork:

    • 首先进入这个项目的主页https://github.com/JakeWharton/butterknife。

    • 点击项目主页右上角的fork图标。

      这时候这个项目就会copy一份到你的github上。

    • 但是有时候你还需要经常保持与原库保持同步,所以你需要使用如下的方式来同步项目。

      git clone https://github.com/tbfungeek/butterknife.git

      进入clone到本地的代码根目录,

      git remote add upstream https://github.com/JakeWharton/butterknife.git

      这时候就可以通过如下命令查看结果:

      git remote -v

    • 同步
      从upstream 仓库 获取对应的分支和对应的提交,这些下载下来的提交存放在本地upstream/master 分支上。

      git fetch upstream

      将本地代码切换到主分支

      git checkout master

      接下来就需要将你下载下来的upstream/master分支merge到本地的master

      git merge upstream/master

      但是这仅仅是同步本地的代码库,要同步到你Github上还需要push到Github上。

  • Clone the Remote

    需要注意的是fork后代码只在你的Github上,如果需要下载到本地进行修改需要使用git clone

例子如下:

git clone https://github.com/tbfungeek/butterknife.git  

这时候本地仓库由 git 维护的三棵“树”组成。第一个是你的工作目录,它持有实际文件;第二个是 缓存区(Index),它像个缓存区域,临时保存你的改动;最后是 HEAD,指向你最近一次提交后的结果。

创建一个本地的分支

当clone完一份代码后,推荐创建一个本地分支进行开发,这样可以避免对master等其他分支产生干扰。

分支是用来将特性开发绝缘开来的。在你创建仓库的时候,master 是“默认的”。在其他分支上进行开发,完成后再将它们合并到主分支上。

  • 在git中提交时,会保存一个Commit对象,它包含一个指向暂存内容快照的指针,作者和相关附属信息,指向该提供对象直接祖先的指针。

  • Git中的分支,本质上仅仅是指向commit对象的可变指针,Git会使用master作为分支的默认名字。

  • HEAD 指向当前分支

git branch branchname 创建分支
git branch 查看分支
git branch -v 查看各分支的最后一次提交
git branch --merged 查看已经合并的分支[除了master分支外,列表中没有*的分支可以使用git branch –d删除]
git branch --no-merged 可以查看尚未合并的分支

切换到最新分支

git checkout branchname 切换到某个分支,这样HEAD就指向了指定的分支了。

本地操作

在介绍Git add/commit 之前需要先介绍下Git到底有哪些目录,各个阶段的文件分别存放在哪个地方:

三个工作区域:

  • 工作目录
  • 暂存区域(是一个简单文件,一般都放在git目录中,这个文件又可以称为索引文件)
  • git 本地代码库

三种状态:

  • 已修改(Modified):某个文件已经被修改但是还没提交保存
    (自上次取出后,做了修改但是还没放到暂存区)
  • *已暂存(staged)*:把已修改的文件放在下一次提交时要保存的清单中了。
    (在工作目录做了修改,并存放到暂存区)
  • *已提交(Committed)*:该文件已经被安全地保存在本地数据库中了
    (git 代码库中保存的特定版本)

在提交之前需要先查看所要提交的文件处于那种状态,所以一般我们提交的时候会先用git status 查看下状态:

nothing to commit(working directory clean)
没有任何跟踪着的文件,没有任何文件在上次提交后更改过,当前没有出现处于未跟踪的新文件。(没有添加,也没有改动)

Untracked files:
(代码库中添加了新的文件,还没执行add)

Change to be committed
(说明当前已经处于暂存状态,如果此时提交,那么该文件此时此刻的版本将被留存在历史记录中,)

Change but not update
(已跟踪文件的内容发生变化,但是还没放到暂存区,要暂存这次更新需要运行git add 命令)

git add 把它们添加到暂存区,使用如下命令:

git add <filename>
git add *
git commit -m "代码提交信息"
现在,你的改动已经提交到了 HEAD,但是还没到你的远端仓库。

Git commit只是将 暂存区域的内容提交到代码库。这里需要确认还有什么修改过的或者新建的文件没有git add过。否则提交的时候不会记录这些还没暂存起来的变化。

从下面图中可以很明显得看出各个操作的具体内容:

在提交的时候一般都会作两个工作就是运行git status 查看各个文件的状态,避免错误提交,
还有就是对比某个文件的内容的修改这个是使用git diff命令:

git diff: 查看 working directory 与 staging area 之间的差异
git diff --cached: 查看 repository 与 staging area 之间的差异
git diff HEAD: 查看 working directory 与 repository 之间的差异

删除文件:

  • 如果是Untracked 类型的文件可以直接使用rm
  • 如果是已经add了需要 git rm -f 但是运行这个命令后,文件直接被删除,
    如果你只是想退回到Untracked,则只需要git rm –cached test.md
  • Commit 后可以使用git rm 了 但是运行这个命令后,文件直接被删除.

回退修改:

这部分比较复杂可以根据下图的情况选择你所需要的:

这里只是介绍下如下几个简单的场景:

当你的修改还没add的时候想反悔怎么办:

git checkout -- <filename>  

此命令会使用 HEAD 中的最新内容替换掉你的工作目录中的文件。已添加到缓存区的改动,以及新文件,都不受影响。

git reset --hard <Commit ID>
  • 替换引用的指向。引用指向新的提交ID。

  • 替换暂存区。替换后,暂存区的内容和引用指向的目录树一致。

  • 替换工作区。替换后,工作区的内容变得和暂存区一致,也和HEAD所指向的目录树内容相同。

  • 这个命令就会导致所有信息的回退包括文件内容,执行后文件内容无法恢复回来。

    git reset  <Commit ID>
  • 即更改引用的指向及重置暂存区,但是不改变工作区。再次提交需要从git add做起

    git reset --soft <Commit ID>
  • 即只更改引用的指向,不改变暂存区和工作区。再次提交从git commit做起即可

假如你想要丢弃你所有的本地改动与提交,可以到服务器上获取最新的版本并将你本地主分支指向到它:

git fetch origin
git reset --hard origin/master

修补提交命令:

git commit --amend,用于对最新的提交进行重新提交以修补错误的提交说明或者错误的提交文件。

忽略某些文件:

有时候我们会有一些文件不需纳入Git管理,也不希望它们总是出现在未跟踪文件列表,我们可以创建一个名字为.gitignore的文件,列出需要忽略的文件模式。
.gitignore格式规范
所有以注释符号#开头的行都会被git忽略
可以使用标准的glob模式匹配
*表示匹配0个或者多个任意字符,
?匹配一个任意字符,
[],[-]
匹配模式最后跟/说明要忽略的是目录
要忽略指定模式以外的文件或者目录可以在模式前加上!取反

查看提交历史 :

git log
git log –p -2 最近两次的更新
git log –stat 仅仅显示简要的增改行数统计
git log –pretty=“oneline”“short”“full”“fuller”
git log –graph 简单图形,展示每个提交所在分支机器分化衍合情况。
这里还有很多属性可查看相关书籍:
下面列出常用的几个命令
git log -n 3 最近三次提交
git log --after(since) = “2014-01-05” 这个时间之后 时间可以是如下格式:2014-01-05
2.years[month][day][hours][minute]
git log --before(untill) = 2014-01-05 这个时间之前
git log -- author 仅显示指定作者相关的提交
git log --committer 仅显示和指定提交者相关的提交
git log -- 路径只关心某个路径下的提交记录
git log --author=xiaohai.lin --since=“2015-01-01” --before=“2016-01-01” —no-merges -- dir/

将代码提交到远程代码库

  • 添远程仓库(这种只会出现在第一次创建本地代码库并从零开始开发完提交到远程代码库的情况):
    如果你还没有克隆现有仓库,并欲将你的仓库连接到某个远程服务器,你可以使用如下命令添加:

    git remote add origin <server>
    git remote add repoShortName git://github.com/paulboone/ticgit.git

    repoShortName:简短仓库名可以用这个名字代替仓库地址了。一般远程服务名为origin
    如此你就能够将你的改动推送到所添加的服务器上去了。

  • 推送数据到远程仓库

    Git push origin master (这里不一定是master 可以是你本地的任何分支)
    [remote name] [branch name]

获取最新代码

Git中可以通过 git fetch 以及 git pull 获取最新的代码,但是二者之间是有所区别的:
git fetch:相当于是从远程获取最新版本到本地,不会自动merge

git fetch origin master:tmp 将代码同步到本地的tmp分支,这时候使用使用git branch 可以看到这里有多出一个分支
git diff tmp 比较分支的差别
git merge tmp 手动merge分支

这是个人比较推崇的一种方式。

git pull:相当于是从远程获取最新版本并merge到本地,相当于git fetch 和 git merge
在实际使用中,git fetch更安全一些,因为在merge前,我们可以查看更新情况,然后再决定是否合并

merge代码

当出现冲突的时候可以使用如下方式解决冲突:

git merge

这时候就会要你选择使用那种merge工具

输入meld就可以使用meld来解决冲突了。

merge 完成后记得要需要执行如下命令以将它们标记为合并成功:
git add
git commit

一般merge完成后就可以删除这个没用的临时分支了:

git branch –d newbranch 删除分支
git branch –D branchname 如果删除这些分支会出现错误,如果执意要删除这些分支可以使用

标签

在软件发布时创建标签,是被推荐的。可以执行如下命令以创建一个叫做 1.0.0 的标签:

git tag 1.0.0 1b2e1d63ff

1b2e1d63ff 是你想要标记的提交 ID 的前 10 位字符。使用如下命令获取提交 ID:


分支操作命令总结:

创建分支 			: git branch branchname
切换到某个分支 : git checkout branchname 这样HEAD就指向了指定的分支了。
新建并切换到新的分支 :git checkout –b ‘newbranchname’
切换到master主分支并合newbranch分支
git checkout master
git merge newbranch
删除分支
Git branch –d newbranch
查看分支
Git branch
查看各分支的最后一次提交
Git branch –v
查看已经合并的分支
Git branch –merged 列表中没有*的分支可以使用git branch –d删除
Git branch –no-merged 可以查看尚未合并的分支
如果删除这些分支会出现错误,如果执意要删除这些分支可以使用
Git branch –D branchname

远程代码库操作命令总结:

git remote –v查看当前配置有哪些远程仓库。
git remote add origin <server> 添加远程分支
重命名远程代码库
git remote rename pd paul 将pd命名为paul
删除远程代码库
碰到远程仓库服务器迁移,或者原来的克隆镜像不再使用,或者参与者不再贡献代码,那么需要移除对应的远程仓库。
Git remote rm paul

团队工作方式

Git 分支工作流


参考资料:

之前写第一篇博客的时候有发现一个问题,就是在使用markdown图片时,运行hexo serv 然后访问本地的博客,这时候图片是可以正常显示出来的,但是部署到github上再访问时就显示不出来了,查了网上的文章,一般都使用图床,但是一来感觉不大可靠,二来也觉得不是非常合理,毕竟到时候第三方博客停止这部分服务那我们这些博客就基本上是报废了,但是找来找去实在没有什么好的方法,就在快准备放弃挣扎投奔图床的队伍中的时候,找到了解决方案。

  1. 修改配置文件*_config.yml*
post_asset_folder:true
  1. 安装 CodeFalling/hexo-asset-image
    npm install https://github.com/CodeFalling/hexo-asset-image --save
    在/source/_posts/目录下建立一个目录,在目录下存放你的md文件,以及图片文件,在md文件中使用如下方式进行应用:
    ![logo](imagefold/logo.jpg) 就可以插入图片。

草稿在很多博客以及邮件上都有用到,你可能会问到使用hexo的,只要你不部署到github上不就也能达到草稿的效果?
但是时候有这种情况,有一篇文章需要耗时很长,但是你在完成这篇文章之前可能会有其他文章需要生成部署,在hexo上默认会产生所有文章并部署到服务器上。
这时候你只能通过将其放到其他文件,改好后再放到source/_posts/目录下。
还有一种情况就是你可能有自己的私密文档不愿意公开,这时候也可以使用草稿的特性。
如何使用草稿这个功能呢?

$ hexo new draft "draft name"

这时候就会在source/_drafts目录下产生对应的文章,在这里的文章在部署的时候不会生成并部署,也就是说这个文件不被显示在页面上,外部指向它的链接也访问不到。所以如果你想把某一篇文章移除显示,又不舍得删除,可以把它移动到_drafts目录之中。所以draft这个目录,相当于草稿箱加垃圾箱。

强行预览草稿:

render_drafts: true
或者
$ hexo server --drafts

个人推荐第二种,毕竟_drafts目录的存在就是为了隐藏你不想公开的文章用的

那如果要发表呢?其实也很简单就是运行如下命令:
$ hexo publish [layout] <filename> ```