作者 群号 C语言交流中心 240137450  微信
15013593099

环境

VS2010UltimTrial1.iso                    http://pan.baidu.com/s/1dEL85kl

VS2010UltimTrialCHS版注冊码    YCFHQ-9DWCY-DKV88-T2TMH-G7BHP

opencv-2.4.9.exe                              http://pan.baidu.com/s/1kVaVwoR

图片地址:                                        f:\img\

操作系统:                                      

                                                         XP     http://pan.baidu.com/s/1bY5SHS

                                                        SP3   http://pan.baidu.com/s/1bAPuGY

执行在虚拟机中                                VM10.0.3 build-1895310   http://pan.baidu.com/s/1dEQsno1

VMKEY                                               5F29M-48312-8ZDF9-A8A5K-2AM0Z       

                                                           1Y0W5-0W205-7Z8J0-C8C5M-9A6MF

读取文件

#include <opencv2\highgui\highgui.hpp>
#include <iostream> using namespace cv;
using namespace std; int main(int argc, const char** argv)
{
Mat img = imread("f:\\img\\lena.jpg");
if (img.empty())
{
cout << "图像载入失败!" << endl;
return -1;
}
//创建一个名字为MyWindow的窗体
namedWindow("MyWindow", CV_WINDOW_AUTOSIZE);
//在MyWindow的窗中中显示存储在img中的图片
imshow("MyWindow", img);
//等待直到有键按下
waitKey(0);
//销毁MyWindow的窗体
destroyWindow("MyWindow");
return 0;
}

 sobel laplace canny

#include <opencv2\opencv.hpp>
#include <iostream> using namespace cv;
using namespace std; int main(int argc, char* argv[])
{
Mat src = imread("f:\\img\\QQ.png");
Mat dst; //输入图像
//输出图像
//输入图像颜色通道数
//x方向阶数
//y方向阶数
Sobel(src,dst,src.depth(),1,1);
imwrite("sobel.jpg",dst);
imshow("sobel",dst);
imshow("src",src); //输入图像
//输出图像
//输入图像颜色通道数
Laplacian(src,dst,src.depth());
imwrite("laplacian.jpg",dst);
imshow("laplacian",dst); //输入图像
//输出图像
//彩色转灰度
cvtColor(src,src,CV_BGR2GRAY); //canny仅仅处理灰度图 //输入图像
//输出图像
//低阈值
//高阈值,opencv建议是低阈值的3倍
//内部sobel滤波器大小
Canny(src,dst,50,150,3);
imwrite("canny.jpg",dst); imshow("canny",dst);
waitKey(); return 0;
}

轮廓

#include <opencv2\opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std; int main()
{ const char* inputImage = "f:\\img\\circle.jpg";
Mat img;
int threshval =100;
img = imread(inputImage,0);
if (img.empty())
{
cout << "Could not read input image file: " << inputImage << endl;
return -1;
} img = img >110;
//namedWindow("Img", 1);
imshow("Img", img); vector<vector<Point> > contours;
vector<Vec4i>hierarchy;
Mat dst = Mat::zeros(img.rows, img.cols, CV_8UC3);
findContours(img, contours,hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE); if( !contours.empty() && !hierarchy.empty() )
{
int idx = 0;
for( ; idx >= 0; idx = hierarchy[idx][0] )
{
Scalar color( (rand()&255), (rand()&255), (rand()&255) );
drawContours( dst, contours, idx, color, 1, 8, hierarchy );
}
}
//namedWindow("Connected Components", 1);
imshow( "Connected Components", dst ); waitKey(0);
return 0;
}

findContours函数。这个函数的原型为:

void findContours(InputOutputArray image, OutputArrayOfArrayscontours, 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表示轮廓的检索模式

CV_RETR_EXTERNAL表示仅仅检測外轮廓

CV_RETR_LIST检測的轮廓不建立等级关系

CV_RETR_CCOMP建立两个等级的轮廓。上面的一层为外边界,里面的一层为内孔的边界信息。假设内孔内另一个连通物体,这个物体的边界也在顶层。

CV_RETR_TREE建立一个等级树结构的轮廓。详细參考contours.c这个demo

method为轮廓的近似办法

CV_CHAIN_APPROX_NONE存储全部的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))==1

CV_CHAIN_APPROX_SIMPLE压缩水平方向,垂直方向,对角线方向的元素,仅仅保留该方向的终点坐标,比如一个矩形轮廓仅仅需4个点来保存轮廓信息

CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain近似算法

offset表示代表轮廓点的偏移量,能够设置为随意值。对ROI图像中找出的轮廓,并要在整个图像中进行分析时,这个參数还是非常实用的。

findContours后会对输入的2值图像改变,所以假设不想改变该2值图像,需创建新mat来存放,findContours后的轮廓信息contours可能过于复杂不平滑。能够用approxPolyDP函数对该多边形曲线做适当近似

contourArea函数能够得到当前轮廓包括区域的大小,方便轮廓的筛选

hough找直线

hough变换

#include <opencv2\opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std; #include <math.h>
#define PI 3.14159265358979 int main(int argc, char *argv[])
{ cv::Mat image = cv::imread("f:\\img\\line.png"); //resize(image,image,Size(image.rows/2, image.cols/2),0,0,CV_INTER_LINEAR);
cv::Mat contours;
cv::cvtColor(image, contours, cv::COLOR_BGR2GRAY);
cv::bitwise_not(contours, contours);
//cv::Canny(image, contours, 155, 350);
std::vector<cv::Vec2f> lines;
cv::HoughLines(contours, lines, 1, PI/180, 180);
//cv::imshow("cany",contours );
std::vector<cv::Vec2f>::const_iterator it= lines.begin();
Mat dst = Mat::zeros(image.rows, image.cols, CV_8UC3);
while (it!=lines.end())
{
float rho= (*it)[0]; // first element is distance rho
float theta= (*it)[1]; // second element is angle theta
if (theta < PI/4. || theta > 3.*PI/4.)// ~vertical line
{
// point of intersection of the line with first row
cv::Point pt1(rho/cos(theta), 0);
// point of intersection of the line with last row
cv::Point pt2((rho - image.rows * sin(theta))/cos(theta), image.rows);
// draw a white line
cv::line( dst, pt1, pt2, cv::Scalar(255), 1);
}
else
{ // ~horizontal line
// point of intersection of the
// line with first column
cv::Point pt1(0,rho/sin(theta));
// point of intersection of the line with last column
cv::Point pt2(image.cols, (rho - image.cols * cos(theta))/sin(theta));
// draw a white line
cv::line(dst, pt1, pt2, cv::Scalar(255), 1);
}
++it;
}
cv::imshow("src", image);
cv::imshow("dst", dst);
waitKey(0);
return 0;
}

概率hough变换

#include <opencv2\opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std; #include <math.h>
#define PI 3.14159265358979
class LineFinder
{
private:
cv::Mat img; // original image
std::vector<cv::Vec4i> lines;
double deltaRho;
double deltaTheta;
int minVote; double minLength; // min length for a line
double maxGap; // max allowed gap along the line
public:
// Default accumulator resolution is 1 pixel by 1 degree
// no gap, no mimimum length
LineFinder() : deltaRho(1),
deltaTheta(PI/180),
minVote(10),
minLength(0.),
maxGap(0.) {}
// Set the resolution of the accumulator
void setAccResolution(double dRho, double dTheta)
{
deltaRho= dRho;
deltaTheta= dTheta;
}
// Set the minimum number of votes
void setMinVote(int minv)
{
minVote= minv;
}
// Set line length and gap
void setLineLengthAndGap(double length, double gap)
{
minLength= length;
maxGap= gap;
}
// Apply probabilistic Hough Transform
std::vector<cv::Vec4i> findLines(cv::Mat& binary)
{
lines.clear();
cv::HoughLinesP(binary, lines, deltaRho, deltaTheta, minVote, minLength, maxGap);
return lines;
}
// Draw the detected lines on an image
void drawDetectedLines(cv::Mat &image, cv::Scalar color = cv::Scalar(255, 255, 255))
{
// Draw the lines
std::vector<cv::Vec4i>::const_iterator it2 = lines.begin();
while (it2 != lines.end())
{
cv::Point pt1((*it2)[0],(*it2)[1]);
cv::Point pt2((*it2)[2],(*it2)[3]);
cv::line( image, pt1, pt2, color, 2);
++it2;
}
}
}; int main(int argc, char *argv[])
{ cv::Mat image = cv::imread("f:\\img\\line.png");
cv::Mat contours;
cv::cvtColor(image, contours, cv::COLOR_BGR2GRAY);
cv::bitwise_not(contours, contours);
//cv::Canny(image, contours, 155, 350);
LineFinder finder;
// Set probabilistic Hough parameters
finder.setLineLengthAndGap(100, 20);
finder.setMinVote(80);
// Detect lines and draw them
std::vector<cv::Vec4i> lines = finder.findLines(contours);
finder.drawDetectedLines(image, cv::Scalar(0, 0, 255));
//cv::namedWindow("Detected Lines with HoughP");
cv::imshow("Detected Lines with HoughP",image);
waitKey(0); }

找圆 hough

#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std; const int kvalue = 15;//双边滤波邻域大小 int main()
{
Mat src_color = imread("f:\\img\\c1.png");//读取原彩色图
imshow("原图-彩色", src_color); //声明一个三通道图像,像素值全为0。用来将霍夫变换检測出的圆画在上面
Mat dst(src_color.size(), src_color.type());
dst = Scalar::all(0); Mat src_gray;//彩色图像转化成灰度图
cvtColor(src_color, src_gray, COLOR_BGR2GRAY);
imshow("原图-灰度", src_gray);
imwrite("src_gray.png", src_gray); Mat bf;//对灰度图像进行双边滤波
bilateralFilter(src_gray, bf, kvalue, kvalue*2, kvalue/2);
imshow("灰度双边滤波处理", bf);
imwrite("src_bf.png", bf); vector<Vec3f> circles;//声明一个向量,保存检測出的圆的圆心坐标和半径
HoughCircles(bf, circles, CV_HOUGH_GRADIENT, 1.5, 20, 130, 38, 10, 50);//霍夫变换检測圆 cout << "x=\ty=\tr=" << endl;
for(size_t i = 0; i < circles.size(); i++)//把霍夫变换检測出的圆画出来
{
Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
int radius = cvRound(circles[i][2]); circle( dst, center, 0, Scalar(0, 255, 0), -1, 8, 0 );
circle( dst, center, radius, Scalar(0, 0, 255), 1, 8, 0 ); cout << cvRound(circles[i][0]) << "\t" << cvRound(circles[i][1]) << "\t"
<< cvRound(circles[i][2]) << endl;//在控制台输出圆心坐标和半径
} imshow("特征提取", dst);
imwrite("dst.png", dst); waitKey();
}

膨胀腐蚀

膨胀就是大了一圈 腐蚀就是小了一圈

#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std; int main(int argc, char *argv[])
{
Mat src, erode_dst, dilate_dst; src = imread("f:\\img\\erode.png");
if (!src.data) {
cout<<"Read image failure."<<endl;
return -1;
}
erode(src, erode_dst, cv::Mat());
dilate(src, dilate_dst, cv::Mat());
namedWindow("src");
namedWindow("erode");
namedWindow("dilate");
imshow("src",src);
imshow("erode",erode_dst);
imshow("dilate",dilate_dst);
waitKey(0); return 0;
}

开闭2

<span style="font-size:14px;">#include <opencv\\cv.h>
#include <opencv\\highgui.h>
#include <stdlib.h>
#include <stdio.h>
IplImage* src = 0;
IplImage* dst = 0;
IplConvKernel* element = 0;
int element_shape = CV_SHAPE_RECT;
//the address of variable which receives trackbar position update
int max_iters = 10;
int open_close_pos = 0;
int erode_dilate_pos = 0;
// callback function for open/close trackbar
void OpenClose(int pos)
{
int n = open_close_pos - max_iters;
int an = n > 0 ? n : -n;
element = cvCreateStructuringElementEx( an*2+1, an*2+1, an, an, element_shape, 0 );
if( n < 0 )
{
cvErode(src,dst,element,1);
cvDilate(dst,dst,element,1);
}
else
{
cvDilate(src,dst,element,1);
cvErode(dst,dst,element,1);
}
cvReleaseStructuringElement(&element);
cvShowImage("Open/Close",dst);
}
// callback function for erode/dilate trackbar
void ErodeDilate(int pos)
{
int n = erode_dilate_pos - max_iters;
int an = n > 0 ? n : -n;
element = cvCreateStructuringElementEx( an*2+1, an*2+1, an, an, element_shape, 0 );
if( n < 0 )
{
cvErode(src,dst,element,1);
}
else
{
cvDilate(src,dst,element,1);
}
cvReleaseStructuringElement(&element);
cvShowImage("Erode/Dilate",dst);
} int main( int argc, char** argv )
{
char* filename = "f:\\img\\oc.png";
if( (src = cvLoadImage(filename,1)) == 0 )
return -1;
printf( "Hot keys: \n"
"\tESC - quit the program\n"
"\tr - use rectangle structuring element\n"
"\te - use elliptic structuring element\n"
"\tc - use cross-shaped structuring element\n"
"\tENTER - loop through all the options\n" );
dst = cvCloneImage(src);
//create windows for output images
cvNamedWindow("Open/Close",1);
cvNamedWindow("src",1);
cvShowImage("src",src);
cvNamedWindow("Erode/Dilate",1);
open_close_pos = erode_dilate_pos = max_iters;
cvCreateTrackbar("iterations", "Open/Close",&open_close_pos,max_iters*2+1,OpenClose);
cvCreateTrackbar("iterations", "Erode/Dilate",&erode_dilate_pos,max_iters*2+1,ErodeDilate);
for(;;)
{
int c; OpenClose(open_close_pos);
ErodeDilate(erode_dilate_pos);
c = cvWaitKey(0);
if( (char)c == 27 )
break;
if( (char)c == 'e' )
element_shape = CV_SHAPE_ELLIPSE;
else if( (char)c == 'r' )
element_shape = CV_SHAPE_RECT;
else if( (char)c == 'c' )
element_shape = CV_SHAPE_CROSS;
else if( (char)c == '\n' )
element_shape = (element_shape + 1) % 3;
}
//release images
cvReleaseImage(&src);
cvReleaseImage(&dst);
//destroy windows
cvDestroyWindow("Open/Close");
cvDestroyWindow("Erode/Dilate");
return 0;
}</span>

距离变换

#include "opencv\\cv.h"
#include "opencv\\highgui.h"
#include <stdio.h>
char wndname[] = "Distance transform";
char tbarname[] = "Threshold";
int mask_size = CV_DIST_MASK_5;
int build_voronoi = 0;
int edge_thresh = 100;
// The output and temporary images
IplImage* dist = 0;
IplImage* dist8u1 = 0;
IplImage* dist8u2 = 0;
IplImage* dist8u = 0;
IplImage* dist32s = 0;
IplImage* gray = 0;
IplImage* edge = 0;
IplImage* labels = 0;
// threshold trackbar callback
void on_trackbar( int dummy )
{
static const uchar colors[][3] =
{
{0,0,0},
{255,0,0},
{255,128,0},
{255,255,0},
{0,255,0},
{0,128,255},
{0,255,255},
{0,0,255},
{255,0,255}
}; int msize = mask_size;
cvThreshold( gray, edge, (float)edge_thresh, (float)edge_thresh, CV_THRESH_BINARY );
if( build_voronoi )
msize = CV_DIST_MASK_5;
cvDistTransform( edge, dist, CV_DIST_L2, msize, NULL, build_voronoi ? labels : NULL );
if( !build_voronoi )
{
// begin "painting" the distance transform result
cvConvertScale( dist, dist, 5000.0, 0 );
cvPow( dist, dist, 0.5 ); cvConvertScale( dist, dist32s, 1.0, 0.5 );
cvAndS( dist32s, cvScalarAll(255), dist32s, 0 );
cvConvertScale( dist32s, dist8u1, 1, 0 );
cvConvertScale( dist32s, dist32s, -1, 0 );
cvAddS( dist32s, cvScalarAll(255), dist32s, 0 );
cvConvertScale( dist32s, dist8u2, 1, 0 );
cvMerge( dist8u1, dist8u2, dist8u2, 0, dist8u );
// end "painting" the distance transform result
}
else
{
int i, j;
for( i = 0; i < labels->height; i++ )
{
int* ll = (int*)(labels->imageData + i*labels->widthStep);
float* dd = (float*)(dist->imageData + i*dist->widthStep);
uchar* d = (uchar*)(dist8u->imageData + i*dist8u->widthStep);
for( j = 0; j < labels->width; j++ )
{
int idx = ll[j] == 0 || dd[j] == 0 ? 0 : (ll[j]-1)%8 + 1;
int b = cvRound(colors[idx][0]);
int g = cvRound(colors[idx][1]);
int r = cvRound(colors[idx][2]);
d[j*3] = (uchar)b;
d[j*3+1] = (uchar)g;
d[j*3+2] = (uchar)r;
}
}
} cvShowImage( wndname, dist8u );
}
int main( int argc, char** argv )
{
char* filename = "f:\\img\\pf.jpg";
if( (gray = cvLoadImage( filename, 0 )) == 0 )
return -1;
cvNamedWindow( "src", 1 );
cvShowImage( "src", gray );
printf( "Hot keys: \n"
"\tESC - quit the program\n"
"\t3 - use 3x3 mask\n"
"\t5 - use 5x5 mask\n"
"\t0 - use precise distance transform\n"
"\tv - switch Voronoi diagram mode on/off\n"
"\tENTER - loop through all the modes\n" );
dist = cvCreateImage( cvGetSize(gray), IPL_DEPTH_32F, 1 );
dist8u1 = cvCloneImage( gray );
dist8u2 = cvCloneImage( gray );
dist8u = cvCreateImage( cvGetSize(gray), IPL_DEPTH_8U, 3 );
dist32s = cvCreateImage( cvGetSize(gray), IPL_DEPTH_32S, 1 );
edge = cvCloneImage( gray );
labels = cvCreateImage( cvGetSize(gray), IPL_DEPTH_32S, 1 );
cvNamedWindow( wndname, 1 ); cvCreateTrackbar( tbarname, wndname, &edge_thresh, 255, on_trackbar );
for(;;)
{
int c; // Call to update the view
on_trackbar(0);
c = cvWaitKey(0);
if( (char)c == 27 )
break;
if( (char)c == '3' )
mask_size = CV_DIST_MASK_3;
else if( (char)c == '5' )
mask_size = CV_DIST_MASK_5;
else if( (char)c == '0' )
mask_size = CV_DIST_MASK_PRECISE;
else if( (char)c == 'v' )
build_voronoi ^= 1;
else if( (char)c == '\n' )
{
if( build_voronoi )
{
build_voronoi = 0;
mask_size = CV_DIST_MASK_3;
}
else if( mask_size == CV_DIST_MASK_3 )
mask_size = CV_DIST_MASK_5;
else if( mask_size == CV_DIST_MASK_5 )
mask_size = CV_DIST_MASK_PRECISE;
else if( mask_size == CV_DIST_MASK_PRECISE )
build_voronoi = 1;
}
}
cvReleaseImage( &gray );
cvReleaseImage( &edge );
cvReleaseImage( &dist );
cvReleaseImage( &dist8u );
cvReleaseImage( &dist8u1 );
cvReleaseImage( &dist8u2 );
cvReleaseImage( &dist32s );
cvReleaseImage( &labels ); cvDestroyWindow( wndname ); return 0;
}

cv1.0入门的更多相关文章

  1. ASP.NET Core 1.0 入门——了解一个空项目

    var appInsights=window.appInsights||function(config){ function r(config){t[config]=function(){var i= ...

  2. ASP.NET Core 1.0 入门——Application Startup

    var appInsights=window.appInsights||function(config){ function r(config){t[config]=function(){var i= ...

  3. Omnet++ 4.0 入门实例教程

    http://blog.sina.com.cn/s/blog_8a2bb17d01018npf.html 在网上找到的一个讲解omnet++的实例, 是4.0下面实现的. 我在4.2上试了试,可以用. ...

  4. 《VC++ 6简明教程》即VC++ 6.0入门精讲 学习进度及笔记

    VC++6.0入门→精讲 2013.06.09,目前,每一章的“自测题”和“小结”三个板块还没有看(备注:第一章的“实验”已经看完). 2013.06.16 第三章的“实验”.“自测题”.“小结”和“ ...

  5. spring web flow 2.0入门(转)

    Spring Web Flow 2.0 入门 一.Spring Web Flow 入门demo(一)简单页面跳转 附源码(转) 二.Spring Web Flow 入门demo(二)与业务结合 附源码 ...

  6. Json.Net6.0入门学习试水篇

    原文:Json.Net6.0入门学习试水篇 前言 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.简单地说,JSON 可以将 JavaScript 对象中 ...

  7. SignalR 2.0 入门与提高

    SignalR 2.0 入门与提高 SignalR 2.0 最近整理了SignalR2.0 部分知识点,原文翻译,由于自己是土鳖,翻译得不好的地方,欢迎指正!仅供各位初学者学习! 第一节. 入门ASP ...

  8. ASP.NET SignalR 2.0入门指南

    ASP.NET SignalR 2.0入门指南 介绍SignalR ASP.NET SignalR 是一个为 ASP.NET 开发人员的库,简化了将实时 web 功能添加到应用程序的过程.实时Web功 ...

  9. Bootstrap3.0入门学习系列

    Bootstrap3.0入门学习系列规划[持续更新]   前言 首先在此多谢博友们在前几篇博文当中给与的支持和鼓励,以及在回复中提出的问题.意见和看法. 在此先声明一下,之前在下小菜所有的随笔文章中, ...

随机推荐

  1. perl install-module.pl DateTime 执行无效问题的解决

    运行./checksetup.pl,总说DateTime模块需要安装,但是执行提示的perl install-module.pl DateTime 多次也还是说DateTime模块需要安装. 在神奇的 ...

  2. CIF、QCIF

    分辨率: 每个像素的存储方式都是YUV   QQCIF:88*72 QCIF:176*144 CIF:352*288 2CIF:704*288 DCIF:584*384 4CIF:704*576   ...

  3. Discuz常见小问题-如何使用QQ登陆

    在首页中找到超链接 往下翻找到QQ互联,注意如果是内网无法开通(需要网站上传之后)

  4. Android访问远程网页取回json数据

    php代码 $array = array(  'username'=>'杨铸',  'password'=>'123456',  'user_id'=>);echo json_enc ...

  5. uva 10721 - Bar Codes(dp)

    题目链接:uva 10721 - Bar Codes 题目大意:给出n,k和m,用k个1~m的数组成n,问有几种组成方法. 解题思路:简单dp,cnt[i][j]表示用i个数组成j, cnt[i][j ...

  6. JPA中的一对多双向关联与级联操作

    学习Spring有两周时间了 , 个人觉得服务端主要实现的是数据关系的维护和数据结构的制定 , 以及由业务需求产生的CRUD , 只要保证对前端提供的接口稳定高效响应 , 具体的前端实现完全不关心. ...

  7. java之Math

    一.Math类 java.lang.Math提供了一系列静态方法用于科学计算:其方法的參数和返回值类型一般为double型. abs     绝对值 acos,asin,atan,cos,sin,ta ...

  8. C++ 智能指针Auto_PTR 分析

    C++的动态内存的分配与释放是个挺折磨人的事情,尤其异常分支复杂时(比如一堆try catch中,各catch里需要做delete 掉相关的堆上分配的内存),极有可能产生内存泄露的情况.C++中提供了 ...

  9. android-使用环信SDK开发即时通信功能及源代码下载

    近期项目中集成即时聊天功能.挑来拣去,终于选择环信SDK来进行开发,选择环信的主要原因是接口方便.简洁.说明文档清楚易懂.文档有android.ios.和后台server端.还是非常全的. 环信官网: ...

  10. Android API之android.provider.ContactsContract.Data

    android.provider.ContactsContract.Data Constants for the data table, which contains data points tied ...