《Instant-OpenCV-for-iOS》-学习笔记-5

打印明信片

本文中我们讨论如何在Objective-C代码中使用C++类。我们创建一个简单的应用程序,使用脸部照片打印出明信片。在本文中我们还学习如何测量程序的运行时间,这样可以在日后优化它。

准备

从例程工程目录中的3张图片拖到自己的工程supporting Files中

  • text.pngtext.png
  • texture.jpgtexture.jpg
  • lena_std.tiflena_std.tif

    步骤

  1. 使用《Instant-OpenCV-for-iOS》-学习笔记-3的工程继续开发。
  2. 创建 PostcardPrinter.cppPostcardPrinter.hpp
  3. PostcardPrinter.hpp中加入如下代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    # ifndef PostcardPrinter_hpp
    # define PostcardPrinter_hpp

    # include "opencv2/core/core.hpp"

    class PostcardPrinter
    {
    public:
    struct Images
    {
    cv::Mat face;
    cv::Mat texture;
    cv::Mat text;
    };

    PostcardPrinter(Images images);
    void print(cv::Mat& postcard) const;

    private:
    void crumple(cv::Mat& image, const cv::Mat& texture,
    const cv::Mat& mask = cv::Mat()) const
    ;

    void alphaBlend(const cv::Mat& src, cv::Mat& dst,
    const cv::Mat& alpha) const
    ;


    Images images_;
    };

    # endif /* PostcardPrinter_hpp */
  1. PostcardPrinter.cpp中添加如下代码实现在PostcardPrinter类中声明的printcrumplealphaBlend等方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    #include "PostcardPrinter.hpp"
    #include "opencv2/imgproc/imgproc.hpp"

    using namespace std;
    using namespace cv;

    PostcardPrinter::PostcardPrinter(Images images)
    {
    images_ = images;
    }

    void PostcardPrinter::print(Mat& postcard) const
    {
    // Prepare postcard
    int border = 50;
    int bottomBorder = border * 4;
    cv::Size postcardSize = cv::Size(images_.face.cols + 2 * border,
    images_.face.rows + border + bottomBorder);
    resize(images_.texture, postcard, postcardSize);

    // Choose places for face and text
    cv::Point shift(border, border);
    cv::Rect faceRoi = cv::Rect(shift, images_.face.size());
    Mat placeForFace = postcard(faceRoi);
    cv::Point origin(border, images_.face.rows + border);
    cv::Rect textRoi(origin + shift, images_.text.size());
    Mat placeForText = postcard(textRoi);

    // Add crumpled face
    Mat crumpledFace = images_.face.clone();
    crumple(crumpledFace, placeForFace);
    crumpledFace.copyTo(placeForFace);

    // Get text's alpha channel
    vector<Mat> textPlanes;
    split(images_.text, textPlanes);
    Mat alpha = textPlanes[3];
    textPlanes.pop_back();
    Mat bgrText;
    merge(textPlanes, bgrText);

    // Add text with crumpling and alpha
    crumple(bgrText, placeForText, alpha);
    alphaBlend(bgrText, placeForText, alpha);
    }

    void PostcardPrinter::crumple(Mat& image, const Mat& texture,
    const Mat& mask) const
    {
    Mat relief;
    cvtColor(texture, relief, CV_BGR2GRAY);
    relief = 255 - relief;

    Mat hsvImage;
    vector<Mat> planes;
    cvtColor(image, hsvImage, CV_BGR2HSV);

    split(hsvImage, planes);
    subtract(planes[2], relief, planes[2], mask);
    merge(planes, hsvImage);

    cvtColor(hsvImage, image, CV_HSV2BGR);
    }

    void PostcardPrinter::alphaBlend(const Mat& src, Mat& dst,
    const Mat& alpha) const
    {
    for (int i = 0; i < src.rows; i++)
    for (int j = 0; j < src.cols; j++)
    {
    uchar alpha_value = alpha.at<uchar>(i, j);
    if (alpha_value != 0)
    {
    float weight = float(alpha_value) / 255.f;
    dst.at<Vec3b>(i, j) = weight * src.at<Vec3b>(i, j) +
    (1 - weight) * dst.at<Vec3b>(i, j);
    }
    }
    }
  2. 在ViewController.mm中的viewDidLoad方法中添加如下代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    #import "ViewController.h"
    #import "PostcardPrinter.hpp"

    @interface ViewController ()

    @end

    @implementation ViewController
    @synthesize imageView;

    - (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    PostcardPrinter::Images images;
    NSString* filePath = [[NSBundle mainBundle]
    pathForResource:@"lena_std" ofType:@"tif"];
    UIImage* image = [UIImage imageWithContentsOfFile:filePath];
    UIImageToMat(image, images.face);

    //FIXME: delete this
    resize(images.face, images.face, cv::Size(512, 512));

    filePath = [[NSBundle mainBundle]
    pathForResource:@"texture" ofType:@"jpg"];
    image = [UIImage imageWithContentsOfFile:filePath];
    UIImageToMat(image, images.texture);
    cvtColor(images.texture, images.texture, CV_RGBA2RGB);

    filePath = [[NSBundle mainBundle]
    pathForResource:@"text" ofType:@"png"];
    image = [UIImage imageWithContentsOfFile:filePath];
    UIImageToMat(image, images.text, true);

    PostcardPrinter postcardPrinter(images);

    cv::Mat postcard;
    int64 timeStart = cv::getTickCount();
    postcardPrinter.print(postcard);
    int64 timeEnd = cv::getTickCount();

    float durationMs =
    1000.f * float(timeEnd - timeStart) / cv::getTickFrequency();
    NSLog(@"Printing time = %.3fms", durationMs);

    if (!postcard.empty())
    imageView.image = MatToUIImage(postcard);
    }

    - (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
    }

    @end
  1. CMD+R 得到效果如下图:
    2015-10-18-0.25.21.jpg

解释

  1. PostcardPrinter 是一个可以用在桌面程序的C++类,他简单调用了一些OpenCv函数。其中crumpling 方法是用于改变图像的强度值(intensity),而这些操作都需要在HSV色彩空间中完成。首先将texture图像转为灰度图存入relief,然后用image的强度通道值(HSV的value通道)减去relief。
  2. UIImageToMat(image, params.text, true);表示转换成带alpha通道的Mat。
  3. OpenCV中有getTickCountgetTickFrequency函数用于测量时间,评估软件性能。乘上1000后的时间单位是毫秒ms
    1000.f * float(timeEnd - timeStart) / cv::getTickFrequency();
  4. 时间的差值要控制在0.5秒内。一般不直接使用getTickCount函数,而是使用宏:
    1
    #define TS(name) int64 t_##name = cv::getTickCount()
         #define TE(name) printf("TIMER_" #name ": %.2fms\n", \
           1000.*((cv::getTickCount() - t_##name) / cv::getTickFrequency()))

《Instant-OpenCV-for-iOS》-学习笔记-4

使用级联分类器检测脸部

本文学习如何使用OpenCV的 cv::CascadeClassifier 类检测脸部。我们加载一个经过训练的分类器XML文件,用这个文件识别脸部,并在识别到的脸部上画个方框。

准备

OpenCv自带经过训练的脸部识别分类器XML文件haarcascade_frontalface_alt2.xml。这个文件可以从 https://github.com/Itseez/opencv/tree/master/data/haarcascades获取到。

步骤

  1. 使用《Instant-OpenCV-for-iOS》-学习笔记-3的工程。
  2. 将haarcascade_frontalface_alt2.xml文件拖到xcode的项目侧边栏的Supporting Files目录下。
  3. 修改 ViewController.h文件。加入CascadeClassifier类型变量声明faceDetector。这就是对象检测器。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #import <UIKit/UIKit.h>
    #import <opencv2/opencv.hpp>
    #import <opencv2/imgcodecs/ios.h>

    using namespace cv;

    @interface ViewController : UIViewController{
    CascadeClassifier faceDetector;
    }
    @property (weak, nonatomic) IBOutlet UIImageView *imageView;

    @end
  1. 修改 ViewController.mm中的viewDidLoad 方法。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    - (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    //加载haarcascade_frontalface_alt2.xml文件
    NSString * cascadePath =[[NSBundle mainBundle] pathForResource:@"haarcascade_frontalface_alt2" ofType:@"xml"];
    faceDetector.load([cascadePath UTF8String]);
    //加载图片文件
    NSString * path = [[NSBundle mainBundle] pathForResource:@"lena_std" ofType:@"tif"];
    UIImage * image = [UIImage imageWithContentsOfFile:path];
    //转换image中的UIImage * 格式图像到Mat格式,结果存到faceImage中
    Mat faceImage;
    UIImageToMat(image, faceImage);
    //转换faceImage中的图像到单通道灰度图像,结果存到gray中
    Mat gray;
    cvtColor(faceImage, gray, COLOR_BGR2GRAY);
    //检查脸部
    std::vector<cv::Rect> faces;
    faceDetector.detectMultiScale(gray, faces, 1.1, 2, 0|CV_HAAR_SCALE_IMAGE, cv::Size(30,30));
    //给所有检查到的脸部画框
    for (unsigned int i=0;i<faces.size();i++){
    const cv::Rect& face = faces[i];
    //得到左上角 和 右下角 坐标
    cv::Point tl(face.x,face.y);
    cv::Point br=tl+cv::Point(face.width,face.height);
    //画框
    Scalar magenta = Scalar(0,128,255);
    rectangle(faceImage, tl, br, magenta,4,8,0);
    }

    //显示结果
    imageView.image = MatToUIImage(faceImage);
    }
  2. CMD+R 编译运行,检查结果
    2015-10-14-10.50.33.jpg

解释

  1. 我们使用了使用《Instant-OpenCV-for-iOS》-学习笔记-3的工程。当然也可以直接建立一个工程。然后加入OpenCV framework文件,在storyboard里加上UIImageView组件。
  2. 本例中,我们使用基于Haar分类器方法的人脸检测器cv::CascadeClassifier。Haar分类器由Paul Viola提出,后由Rainer Lienhart发展。
  3. haarcascade_frontalface_alt2.xml文件包含了用于检测脸部正面特征的分类器参数。
  4. 加载参赛需要将NSString对象转化为std::string对象。使用UTF8String方法将NSString对象转化为std::string对象。
  5. 使用CascadeClassifier类的detectMultiScale方法在图像中找到脸部区域。
  6. 使用cv::rectangle函数在检测结果区域上加方框。
  7. 可以使用不同的图片或者不同的分类器XML文件进行试验。比如使用haarcascade_eye.xml可以得到这样的效果
    2015-10-14-11.57.28.jpg

《Instant OpenCV for iOS》 学习笔记(3)

连接OpenCV到iOS项目中

本文学习在项目中添加OpenCV库的设置方法和调用OpenCV库函数的方法。
学习UIImage和cv::Mat之间相互转换。

准备

下载ios版本的 opencv库文件 opencv2.framework本例中使用3.0。解压。

步骤

  • 继续使用学习笔记(2)的工程。将解压所得的framework拖入项目侧边栏中
    2015-10-09-10.40.58.jpg
  • 在ViewController.h中加入opencv头文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #import <UIKit/UIKit.h>
    #import <opencv2/opencv.hpp>
    #import <opencv2/imgcodecs/ios.h>

    using namespace cv;

    @interface ViewController : UIViewController{
    UIImage* image;
    Mat cvImage;
    }

    @property (weak, nonatomic) IBOutlet UIImageView *imageView;

    @end
  • 修改ViewController.m文件名为ViewController.mm\.mm*表示object c++ 文件。因为opencv是用c++写的。
  • 编辑ViewController.mm中的viewDidLoad()方法。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    	- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    image = [UIImage imageNamed:@"lena_std.tif"];
    if (image!=nil) {
    //转换image中的UIImage * 格式图像到Mat格式,结果存到cvImage中
    UIImageToMat(image, cvImage);
    }

    if (!cvImage.empty()) {
    Mat cvGrayImage;
    //转换cvImage中的图像到单通道灰度图像,结果存到cvGrayImage中
    cvtColor(cvImage, cvGrayImage, COLOR_BGR2GRAY);
    //高斯模糊去除cvGrayImage中微小的边缘,结果存到cvGrayImage中
    GaussianBlur(cvGrayImage, cvGrayImage, cv::Size(5,5), 1.2, 1.2);
    //Canny算法得到cvGrayImage中图像的边缘,结果存到cvGrayImage中
    Canny(cvGrayImage, cvGrayImage, 0, 50);
    //设置cvImage中图像的所有像素为灰度色
    cvImage.setTo(Scalar::all(255));
    //设置cvImage中图像的边缘部分像素为蓝色
    cvImage.setTo(Scalar(0,128,255,255),cvGrayImage);
    //转换cvImage中的Mat格式图像到UIImage* 格式并且在imageView组件显示
    imageView.image=MatToUIImage(cvImage);
    }
    }
  • 运行程序查看效果。
    2015-10-10-8.58.07.jpg

解释

  1. framework 简化了处理依赖关系的过程。framework封装了头文件和bin文件,这些文件的依赖关系由xcode处理,我们无须手动处理include 路径。我们也不需要手动处理不同架构(比如armv7,armv7s和x86),xcode会根据不同的编译配置自动寻找合适的库。
  2. 通常ios应用程序用Objective-C语言,头文件是 *.h , 源代码文件 *.m。Objective-C语言是C语言的超集,所以可以在Objective-C文件中加入C语言。同理,Objective-C++文件中可以加入C++。OpenCv是用C++写的,所以需要使用Objective-C++。Objective-C++文件的后缀名是 *.mm
  3. 加入using namespace cv;声明使用opencv的命名域空间。这样可以在后续调用opencv方法时显得简化一些。例如cv::Mat 只要写成 Mat就好了。
  4. 在viewDidLoad()中,我们调用UImageToMat方法转换UIImage对象到cv::Mat对象。但请不要频繁调用这个方法,这样做会消耗内存影响程序性能。UImageToMatMatToUIImage方法在头文件中定义。
  5. 在转换完成图像后,使用opencv做了一些简单的图像处理。首先是转换cvImage中的图像到单通道灰度图像。然后使用高斯模糊去除cvGrayImage中微小的边缘;接着使用Canny算法检测cvGrayImage中图像的边缘。为了显示效果,创建了一幅白色背景,边缘像素设置为蓝色的图像。最后调用MatToUIImagecv::Mat对象转回UIImage并在屏幕上显示。
  6. 在viewDidLoad()中,使用:

image = [UIImage imageNamed:@"lena_std.tif"];
方法加载图片有内存溢出的风险。
可以使用如下两句替代:

1
2
NSString * path = [[NSBundle mainBundle] pathForResource:@"lena_std" ofType:@"tif"];
image = [UIImage imageWithContentsOfFile:path];

《Instant OpenCV for iOS》 学习笔记(2)

从工程目录(supporting)显示图像

ios应用程序在supporting目录存放图像文件。本文我们学习如何添加图像文件到资源文件夹,如何加载图像文件到UIImage对象并显示。我们将会用到UIImageView组件。

准备

  • 准备一张照片文件 http://lenna.org 这张叫做lenna的照片在各种图像处理教科书中被使用到,简直可以说是图像处理里的hello word御用照片了。从这个网站可以了解到这张照片的来历:)。

步骤

  • 新建一个工程具体步骤详见《Instant OpenCV for iOS》 学习笔记(1))或者直接在原来的工程上继续开发(我选择后者)。

  • 拖入下载的图片文件到工程supporting Files 目录下2015-10-03-01.jpg

  • 加入ImageView 到我们的View视图中: 打开StoryBoard Editor -> 从Object Library 中选择Image View 组件拖到Story Board的View中 2015-10-03-02.jpg
  • 在ViewController.h中添加变量image:
1
2
3
4
5
6
7
#import <UIKit/UIKit.h>

@interface ViewController : UIViewController{
UIImage* image;
}

@end
  • 然后打开storyBoard Editor 并调出Assistant Editor 并在Assistant Editor 中打开ViewController.h 。此时Xcode的界面显示左右两部分区域。左边是UIImageView的StoryBoard,而右面是显示ViewController.h的Assistant Editor。
  • 从左边StoryBoard按住Ctrl 鼠标按住选择UIImageView 拖到右边的ViewController.h代码界面中。2015-10-03-03.jpg
  • 在弹出的对话框中输入变量名称“imageView”。2015-10-03-04.jpg
  • 自动生成代码后,ViewController.h的代码如下:
1
2
3
4
5
6
7
8
#import <UIKit/UIKit.h>

@interface ViewController : UIViewController{
UIImage* image;
}
@property (weak, nonatomic) IBOutlet UIImageView *imageView;

@end
  • 在ViewController.m中添加代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController
@synthesize imageView;

- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
image = [UIImage imageNamed:@"lena_std.tif"];
if (image!=nil) {
imageView.image=image;
}
}

- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}

@end
  • 最后 command + r 编译运行
  • 在仿真器上的运行结果
    2015-10-03-05.jpg

注释

  • iOS 的GUI开发使用MVC设计模式。这种模式把应用程序分成界面部分(View)、模型(算法)部分(Model)、控制器(用户交互)部分(Controller)。一些简单的程序只需要View 和 Controller 就可以了,因为逻辑比较简单,无需专门分个Model部分出来。
  • iOS程序的一个View就对应一个storyboard单元。这些单元最终存在*.storyboard 文件中(在本例中,就是Main.storyboard文件)。在Xcode中我们使用集成的Interface Builder工具来编辑 Main.storyboard。
  • 每个view通常对应一个Controller。一般新建一个project时xcode默认创建一个ViewController类(ViewController.h和ViewController.m)。
  • 本例中从storyboard中连线UIImageView到ViewController.h中后xcode自动添加了IBOutlet property用于声明一个接口。IBOutlet 是一个特殊的宏,用于向xcode表明这个声明的property(本例中是UIImageView *imageView)是链接到View单元上。
  • 默认情况下,在controller的接口中添加变量都是自私有的,因此需要对变量添加set和get方法才可以在这个类之外的地方访问这个变量。@property 和 @synthesize 关键字告诉Objective-C编译器自动生成set和get方法。
  • (void)viewDidLoad方法在ViewController加载时被调用。因此在这里添加显示图像的代码。

《Instant OpenCV for iOS》 学习笔记(1)

从iOS开始

本文简要介绍设置iOS开发环境以及运行一个“Hello World”程序。

准备

  1. 一台Mac OS X 台式机或笔记本
  2. iOS 设备(比如iphone)
  3. Xcode
  4. 这本书的例子程序源码,可以到http://www.packtpub.com/support注册然后会从邮箱收到源代码的下载链接。

步骤

  1. 在xcode创建新工程
    • 菜单栏:File -> new -> Project
    • 选择 Single View Application
    • 填写 Product Name (比如填写C01)
    • 选择 Language 为 Objective-C
    • 不要勾选 Use Core Data, Include Unit Tests,Include UI Tests
    • 按 Next 选择保存路径 然后finish 工程就建好了。
  2. 编译ViewController.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSLog(@"Hello World!");

[[[UIAlertView alloc]
initWithTitle:@"喂,这里!"
message:@"欢迎来到Opencv开发社区!"
delegate:nil cancelButtonTitle:@"继续"
otherButtonTitles:nil, nil]
show];
}

- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}

@end
  1. 编译运行
    在emulator上看到结果
    1.png

在macos上搭建pyqt环境

今天在mpb上搭建了pyqt + qt + pycharm / eclipse+pydev
用来学习pyqt。
pyqt 和 qt 都是用 homebrew 安装的,so easy。

1
2
3
brew install python
brew install pyqt
brew install qt

pycharm的安装就是上pycharm官网下载安装包后安装一下。

eclipse+pydev 是安照
python+Eclipse+pydev环境搭建操作的,也没有什么问题。

只是在上述两个IDE的配置过程中。python interpreter配置时需要使用/usr/local/bin/python,不要用 系统自带的/usr/bin/python。否则一直找不到pyqt库。
因为homebrew把python装到/usr/local/目录下了,pyqt也装到/usr/local/lib/python2.7/site-packages/ 下了。

使用Xcode7免费真机调试iOS应用程序

今天在给我的mbp升级xcode 在说明中看到这样一段文字:

Now everyone can run and test their own app on a device—for free. You can run and debug your own creations on a Mac, iPhone, iPad, iPod touch, or Apple Watch without any fees, and no programs to join. All you need to do is enter your free Apple ID into Xcode. You can even use the same Apple ID you already use for the App Store or iTunes. Once you’ve perfected your app the Apple Developer Program can help you get it on the App Store.

这是真的么?百度了一下,是真的。太好了,这下可以剩下99美刀了。
马上试了一下,步骤如下:

1.运行Xcode后,点击菜单中的Preferences…进入Accounts标签
2.左边栏选自己的Apple ID, 右边可以看到

Name iOS MAC
xxx free free

3.按下右边栏中右下角的View Details…按钮打开Details对话框

4.在Details对话框中可以看到:

Signing Identities Action
iOS Development Create
iOS Distribution Create
Mac Development Create
Mac App Distribution Create
Mac Installer Distribution Create
Developer ID Application Create
Developer ID Installer Create

Create表示灰色,不能选择。

5.点击 iOS Development和Mac Development栏对应的Create钮。然后这两个
Create钮就消失了。接着点击右下角的Done按钮。

6.随便打开一个iOS工程。usb连上老婆的iphone6 。

7.Xcode 上的iOS Devce下拉菜单中多出了iphone6,太棒了。

8.选择 iphone6 然后猛击运行。由于第一次调试需要添加Provisioning Profile,xcode弹出一个Issue消息,点击的Issue旁点Fix,一切就都由Xcode搞定了,最终会生成对应App ID的描述文件,这时编译链接项目,运行调试就可以了。

9.发现iphone6中竟然多出了那个APP。断开usb线也可以在iphone上运行,就和其他APP一样。

在XCode中使用OpenCV

  1. 创建一个空的command line工程。
  2. 写opencv代码
  3. 添加lib文件:右键点击工程名,选择“Add files to..”,在文件选择对话框弹出来时输入“/”,在弹出的路径框中输入:/usr/local/lib,全选该文件夹下的全部dylib文件,添加至工程。
  4. 添加lib文件查找支持: 点击工程名文件,进入“Build Settings”选项卡,在“Library Search Paths”栏中输入“/usr/local/lib”
  5. 添加头文件:点击工程名文件,进入“Build Settings”选项卡,在“Header Search Paths”栏中输入:“/usr/local/include /usr/local/include/opencv”
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Search Paths 

Header Search Paths
/usr/local/include

Library Search Paths
/usr/local/lib
/usr/local/Cellar/opencv/2.4.11_1/lib

opencv2\core\

Build Phases
Link Binary With Libraries
/usr/local/Cellar/opencv/2.4.11_1/lib
  1. 编译运行整个工程,运行成功~~

正手弧圈-手腕外展

练习拉弧圈球时一直没想明白所谓的“手腕发力”到底是怎么做。于是在乒乓网上搜了一下。发现有这样一些文字摘录如下:

基本概念:将右臂伸直并向右水平地抬起,五指自然伸直、掌心朝下:手腕向地面方向的运动为屈,向掌背方向的运动为伸(或挺);手腕向姆指方向运动为收,向小指方向运动为展。

引拍尾期动作的手腕外展并不只是手掌向小指方向的运动,而是先以手掌的伸(挺)到位后、再辅以手掌向小指方向的运动(展)所合成的。手腕外展正确地动作过程应该是拉手到位后适度地伸腕、这时的拍面是接近垂直于地面的稍前倾状态,然后由手指发力控拍使手腕向小指方向运动,使拍面接近于与地面水平,这个手腕的复合运动才是手腕外展的基本内容。手腕外展后小臂与手腕都有紧张的受力感觉就对了,只有手腕受力是没有伸、只有展的错误动作。因此,手腕的外展应该是手腕的伸配合展的”伸、展”动作,手掌只向小指方向的运动只能叫展而不是真正意义上的弧圈技术中的手腕外展。
手腕由外展转内收是弧圈发力过程中的一部分重要构成。在引拍过程的尾期时使手腕外展的动作过程是对的,这一点应肯定,所以也有人将手腕外展的过程称为二次引拍。