接着上篇FLANN特征匹配,从上篇可以知道,如果特征匹配时全部是用线进行匹配,匹配效果并不能达到一目了然的效果
那么,可不可以把匹配到的结果用矩形或圆表示出来呢 当然可以,这就是平面对象识别


关于基于透视变换的平面对象识别
主要用到两个新的API
cv::findHomography() – 发现两个平面的透视变换,生成透视变换矩阵
cv::perspectiveTransform() – 进行透视变换


关于透视变换

透视变换(Perspective Transformation)可以对图片进行校正 也可以通过透视变换进行图像的平面识别

透视变换(Perspective Transformation)是指利用透视中心、像点、目标点三点共线的条件,
按透视旋转定律使承影面(投影面)绕迹线(透视轴)旋转某一角度,破坏原有的投影光线束,
仍能保持承影面上投影几何图形不变的变换

单应矩阵透视变换进行图像矫正,最少需要四个对应点对


关于基于透视变换的图像校正

透视变换对畸变图像的校正需要取得畸变图像的一组4个点的坐标,和目标图像的一组4个点的坐标,通过两组坐标点可以计算出透视变换的变换矩阵,之后对整个原始图像执行变换矩阵的变换,就可以实现图像校正

图像校正API
cv::warpPerspective对翘曲图像进行校正显示


代码演示

#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui_c.h>
#include <opencv2/xfeatures2d.hpp>
#include <iostream>
#include <math.h>using namespace cv;
using namespace std;
using namespace cv::xfeatures2d;int Osize = 3;
Mat SenceIMG, ObjIMG, dst;void FLANNdetector(int, void*);
void WarpPerspective(int, void*);
int main()
{ObjIMG = imread("D:/实验台/机器视觉/测试图片/自由女神小.jpg", IMREAD_GRAYSCALE);//训练图像SenceIMG = imread("D:/实验台/机器视觉/测试图片/自由女神像.jpg", IMREAD_GRAYSCALE);//查询图像if (SenceIMG.empty() || ObjIMG.empty())//如果SenceIMG这个数据库属性为空{cout << "无法打开" << endl;return -1;}imshow("训练图像", SenceIMG);imshow("查询图像", ObjIMG);namedWindow("透视变换画出目标轮廓的效果", CV_WINDOW_AUTOSIZE);createTrackbar("最大允许重投影错误阈值", "透视变换画出目标轮廓的效果", &Osize, 150, FLANNdetector);FLANNdetector(0, 0);WarpPerspective(0, 0);waitKey(0);return 0;
}

FLANN特征检测

void FLANNdetector(int, void*)
{//copy自FLANN特征检测项目的代码 int minHessian = 400;//特征检测器阈值Ptr<SURF> detector = SURF::create(minHessian);//构建SURF类的特征点检测器vector<KeyPoint>keypointOBJ; // 设置用于存放第一张图特征点信息的 KeyPoint类的集合向量 keypointsvector<KeyPoint>keypointSCENE;//同上 待匹配的第二张图的特征点信息Mat descriptorOBJ, descriptorSCENE; //建立两个描述符集矩阵分别存放图一的查询描述集和图二的训练描述集合//进行对两张需要进行匹配的图像的特征提取和描述符信息的计算detector->detectAndCompute(ObjIMG, Mat(), keypointOBJ, descriptorOBJ);detector->detectAndCompute(SenceIMG, Mat(), keypointSCENE, descriptorSCENE);//todocv :: Feature2D :: detectAndCompute检测特征点并计算其描述子的函数(使用detector这个检测器)基于Flann类型的描述符匹配器FlannBasedMatcher matcher;//todo建立查询训练集中的描述符得出的 匹配项描述符 所需要的动态向量DMatch类数组vector<DMatch>matches;//未进行筛选前的匹配描述符matcher.match(descriptorOBJ, descriptorSCENE, matches);//todovoid cv::DescriptorMatcher::match使用建立好的Flann匹配器matcher进行匹配//匹配相关度最高的特征点过滤不相干的特征点double minDist = 1000;double maxDist = 0;//通过遍历两个匹配的特征向量之间的欧氏距离(距离越近匹配度越高)进行精确特征点的筛选for (int i = 0; i < descriptorOBJ.rows; i++){double dist = matches[i].distance;//读取匹配特征描述符集中的欧式距离if (dist > maxDist){maxDist = dist;//寻找距离最大值}if (dist < minDist){minDist = dist;//寻找距离最小值}}printf("最大欧氏距离为 %f\n", maxDist);printf("最小欧氏距离为 %f\n", minDist);//todo建立存储过滤欧氏距离时大于阈值的匹配描述符的DMatch类向量矩阵goodMatchesvector<DMatch>goodMatches; //被压入此矩阵内的匹配描述符信息将被认为是准确的匹配描述符进行绘制for (int i = 0; i < descriptorOBJ.rows; i++){double dist = matches[i].distance;//读取匹配特征描述符集中的欧式距离if (dist < max(2*minDist, 0.02)){goodMatches.push_back(matches[i]);}}Mat MatchesIMG;drawMatches(ObjIMG, keypointOBJ, SenceIMG, keypointSCENE, goodMatches, MatchesIMG, Scalar::all(-1), Scalar::all(-1), vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);//todovoid cv::drawMatches 对进行匹配的两张图片水平排列,然后在最佳匹配的点之间绘制直线imshow("FLANN特征匹配结果", MatchesIMG);//  imshow("descriptorOBJ-查询描述符集", descriptorOBJ);
//  imshow("descriptorSCENE-训练描述符集", descriptorSCENE);//?copy自 FLANN特征检测项目代码到此为止

平面对象识别 findHomography+perspectiveTransform对最佳匹配keypoint关键点进行几何变换

 //建立两组存放透视变换矩阵坐标点的向量 (PT为透视变换PerspectiveTransformation)vector<Point2f>PTOBJ;//存放最佳匹配的 匹配项描述符集中的 训练图像的特征描述符的坐标位置信息(浮点型二维x,y)vector<Point2f>PTSCENE;//存放最佳匹配的 匹配项描述符集中的 查询图像的特征描述符的坐标位置信息(浮点型二维x,y)//todo有了这两组位置信息 就为训练图像和目标图像中的目标 构建了坐标对应关系 //todo遍历最佳匹配 匹配项描述符集 并将训练图像和查询图像的特征描述符中的坐标信息压入透视变换的矩阵坐标向量中(利用这两组值进行投射矩阵的计算)for (size_t i = 0; i < goodMatches.size(); i++){PTOBJ.push_back(keypointOBJ[goodMatches[i].queryIdx].pt);  // queryIdx:是测试图像(训练图像)的特征点描述符(descriptorOBJ)的下标,同时也是描述符对应特征点(keypointOBJ)的下标PTSCENE.push_back(keypointSCENE[goodMatches[i].trainIdx].pt);  //trainIdx:是样本图像(查询图像)的特征点描述符的下标,同样也是相应的特征点的下标cout << endl;cout << "被压入的第" << i + 1 << "对训练图像的特征描述符在过滤后的匹配项描述符集中的索引为" << goodMatches[i].queryIdx << "此描述符对应的关键点的坐标为" << keypointOBJ[goodMatches[i].queryIdx].pt << endl;cout << "被压入的第" << i + 1 << "对查询图像的特征描述符在过滤后的匹配项描述符集中的索引为" << goodMatches[i].trainIdx << "此描述符对应的关键点的坐标为" << keypointSCENE[goodMatches[i].trainIdx].pt << endl;cout << endl;/*注:在提取特征点描述符坐标时虽然 keypointOBJ.pt 和 keypointSCENE[goodMatches[i].trainIdx].pt的意义一样 都是提取特征描述符坐标的坐标信息 但是一定要写成  keypointSCENE[goodMatches[i].trainIdx].pt 因为goodMatches[i].trainIdx].pt 才是过滤后的匹配度高的特征点!!*/}//获取了训练图像的特征描述符的坐标信息 和 查询图像的特征描述符的坐标信息 利用两个坐标点集就可以生成一个透视变换矩阵// 使用findHomography函数 计算多个二维点对之间的最优投射矩阵 H (3行*3列) 使用最小均方误差 或 RANSAC方法Mat H = findHomography(PTOBJ, PTSCENE, RANSAC,Osize);//todocv::findHomography(单应性矩阵计算) 通过源平面坐标矩阵(PTOBJ)和目标平面坐标矩阵(PTSCENE)之间的坐标对应关系 计算透视变换矩阵H// 1.InputArray   srcPoints -- 源平面(训练图像) 中点的坐标矩阵,可以是CV_32FC2类型,也可以是vector<Point2f>类型// 2.InputArray   dstPoints -- 目标平面(查询图像) 中点的坐标矩阵,可以是CV_32FC2类型,也可以是vector<Point2f>类型// 3.int     method = 0 -- 用于计算单应性矩阵的方法 有以下四个参数  (此值需按情况调节)// 0-利用所有点(常规方法)//RANSAC 基于RANSAC的鲁棒性算法//LMEDS 最小中值鲁棒算法//RHO 基于PROSAC的鲁棒算法5// 4.double   ransacReprojThreshold = 3 -- 将点对视为内点的最大允许重投影错误阈值 (仅用于RANSAC和RHO方法) (此值需按情况调节)//原图像的点经过变换后点与目标图像上对应点的误差,超过误差就认为是异常值,该参数通常设置在1到10的范围内// 5.OutputArray    mask = noArray() -- 可选输出掩码矩阵,通常由鲁棒算法(RANSAC或LMEDS)设置。 请注意,输入掩码矩阵是不需要设置的 (此值多数情况下不需要使用)// 6.const int   maxIters = 2000 -- RANSAC算法的最大迭代次数,默认值和最大值皆为2000 (此值需按情况调节)// 7.const double    confidence = 0.995--可信度值,取值范围为0到1 (此值越大越准确)//注 :该函数 根据PTOBJ的顶点数据与PTSCENE的顶点数据,返回由PTOBJ变换到PTSCENE的变换矩阵Himshow("H",H);//显示投射矩阵H的信息vector<Point2f>PTOBJCorners(4);//建立 存储进行透视变换前 训练图像的角点vector<Point2f>PTSceneCorners(4);//建立存储对透视变换前训练图像的角点进行透视变换后 在合成的匹配图像中绘制的矩形的四个角点坐标//设置训练图像的四个角点位置为透视变换时需要输入的训练图像的四个角点信息PTOBJCorners[0] = Point(0, 0);   //左上角(第一点)坐标PTOBJCorners[1] = Point(ObjIMG.cols, 0); //右上角(第二点)坐标PTOBJCorners[2] = Point(ObjIMG.cols, ObjIMG.rows); //右下角(第三点)坐标PTOBJCorners[3] = Point(0, ObjIMG.rows); //右下角(第三点)坐标cout << " 透视矩阵变换前 在合成的匹配图像中绘制的标记目标的矩形的四个角点坐标为" << endl << PTSceneCorners << endl;//todo有了训练图像的目标的四个角点的坐标就可以通过变换矩阵H配合perspectiveTransform透视矩阵变换得到查询图像上目标对应训练图像的四个角点的坐标//使用cv2.perspectiveTransform()来找目标,它需要至少4个正确的点来进行透视变换perspectiveTransform(PTOBJCorners, PTSceneCorners, H);//todocv::perspectiveTransform() 利用计算出的透视变换矩阵H 执行矢量的透视矩阵变换(将训练图像的四个角点投影到一个合成图像的对应的四个角点)// 1.InputArray src -- 输入的训练图像的四个角点坐标信息(双通道或三通道浮点数组/图像)// 2.OutputArray dst -- 输出透视变换前训练图像的角点用变换矩阵H进行透视变换后 在合成的匹配图像中计算出的绘制的矩形的四个角点坐标信息// 3.InputArray m -- 3x3或4x4浮点转换矩阵H/*注:透视矩阵变换的工作过程 1.取的需要进行透视变换的训练图像的四个角点坐标(PTOBJCorners)2.用之前生成的用于计算透视转换矩阵H(H为投射矩阵)进行对原角点的透视转换 (H)3.转换完毕的角点为在合成图像上绘制矩形的角点(PTSceneCorners)*/cout << " 透视矩阵变换前 训练图像的四个角点坐标为" << endl << PTOBJCorners << endl;cout << " 透视矩阵变换后 在合成的匹配图像中绘制的标记目标的矩形的四个角点坐标为" << endl << PTSceneCorners << endl;// draw line   因为matchesImg是两张图像的合成,所以若要在matchesImg上显示找到的书本的位置,x坐标需要偏移img1.colsline(MatchesIMG, PTSceneCorners[0] + Point2f(ObjIMG.cols, 0), PTSceneCorners[1] + Point2f(ObjIMG.cols, 0), Scalar(0, 0, 255), 2, 8, 0);line(MatchesIMG, PTSceneCorners[1] + Point2f(ObjIMG.cols, 0), PTSceneCorners[2] + Point2f(ObjIMG.cols, 0), Scalar(0, 0, 255), 2, 8, 0);line(MatchesIMG, PTSceneCorners[2] + Point2f(ObjIMG.cols, 0), PTSceneCorners[3] + Point2f(ObjIMG.cols, 0), Scalar(0, 0, 255), 2, 8, 0);line(MatchesIMG, PTSceneCorners[3] + Point2f(ObjIMG.cols, 0), PTSceneCorners[0] + Point2f(ObjIMG.cols, 0), Scalar(0, 0, 255), 2, 8, 0);//Point2f(SenceIMG.cols, 0)为偏移量dst=SenceIMG;line(dst, PTSceneCorners[0], PTSceneCorners[1], Scalar(0, 0, 255), 2, 8, 0);line(dst, PTSceneCorners[1], PTSceneCorners[2], Scalar(0, 0, 255), 2, 8, 0);line(dst, PTSceneCorners[2], PTSceneCorners[3], Scalar(0, 0, 255), 2, 8, 0);line(dst, PTSceneCorners[3], PTSceneCorners[0], Scalar(0, 0, 255), 2, 8, 0);imshow("透视变换画出目标轮廓的效果", MatchesIMG); // 在合成的matchesImg上显示找到的书本imshow("透视变换画出目标轮廓的效果不使用偏移量绘制", dst); // 在原训练图上显示找到的书本//todo注意!训练图像的大小对匹配结果至关重要 如果训练图像尺寸太小 会导致无法绘制
}

效果

实战!利用透视变换矩阵h和和翘曲透视变换对 翘曲图像进行校正
利用findHomography计算投射矩阵+warpPerspective透视变换进行翘曲图像的校正

void WarpPerspective(int, void*)
{Mat Src = imread("D:/实验台/机器视觉/测试图片/书本1.jpg");//首先要选中翘曲图像中的书本目标的四个角点的坐标值并压入相应的向量矩阵中vector<Point2f> PTSsrc;PTSsrc.push_back(Point2f(65, 62));//书本目标左上角PTSsrc.push_back(Point2f(226, 74));//书本目标右上角PTSsrc.push_back(Point2f(233, 299));//书本目标右下角PTSsrc.push_back(Point2f(26, 286));//书本目标左下角//其次建立大小为(300*400)的校正图像矩阵 并将校正图像的四个角点坐标值依次压入相应的向量矩阵中vector<Point2f> PTSdst;PTSdst.push_back(Point2f(0,0));//校正图像左上角PTSdst.push_back(Point2f(300, 0));//校正图像左上角PTSdst.push_back(Point2f(300, 400));//校正图像左上角PTSdst.push_back(Point2f(0, 400));//校正图像左上角//todo建立翘曲和校正两个图像的各四个角点坐标 是为了对应他们彼此的坐标关系 (有了这个坐标关系就可以计算他们的投射矩阵H 有了投射矩阵就可以进行依照彼此坐标的联系进行透视变换)Mat h = findHomography(PTSsrc, PTSdst);//todocv::findHomography(单应性矩阵计算) 通过源平面(PTOBJ)和目标平面(PTSCENE)之间的坐标对应关系 生成投射矩阵H// 1.InputArray    srcPoints -- 源平面(翘曲图像中的目标的四个角点) 的坐标矩阵,可以是CV_32FC2类型,也可以是vector<Point2f>类型// 2.InputArray    dstPoints -- 目标平面(建立的校正后存放目标的矩阵图像的四个角点)  的坐标矩阵,可以是CV_32FC2类型,也可以是vector<Point2f>类型//返回值:一个Mat类型的矩阵h,作为接下来投射变换的参数// 3.int  method = 0  //3.int    method = 0 -- 用于计算单应性矩阵的方法 已给出准确的源平面和目标平面的对应性矩阵信息  直接利用所有点进行计算即可( 0-利用所有点(常规方法))// 4.double    ransacReprojThreshold = 3 默认值即可// 5.OutputArray    mask = noArray() -- 默认值即可// 6.const int    maxIters = 2000 -- 默认值即可// 7.const double  confidence = 0.995-默认值即可imshow("透视变换矩阵H",h);//建立透视变换后的校正图像的矩阵Mat ResultIMG;warpPerspective(Src, ResultIMG, h,Size(300,400));//todocv::warpPerspective(翘曲透视变换)对翘曲图像进行透视变换并生成校正图像//  1.cv::InputArray src  -- 输入图像(将h中的输入图像的书本目标的四个角点的坐标 透视变换到 输出图像的四个角点坐标)//    2.cv::OutputArray dst  -- 输出图像(把变换矩阵h中的四个目标图像角点的坐标对应输出图像的角点坐标进行透视变换)//  3.cv::InputArray M  -- 输入的 3x3 变换矩阵h(此矩阵变换了需要校正的目标的四个角点标PTSsrc 和校正后准备好的新角点坐标PTSdst)//   4.cv::Size dsize  -- 输出图像的大小//  5.int flags = cv::INTER_LINEAR  -- 输出图像的插值方法(线性插值或者最近邻插值)//  6.int borderMode = cv::BORDER_CONSTANT  -- 图像边界的处理方式 可选(BORDER_CONSTANT或BORDER_REPLICATE)//  7.const cv::Scalar& borderValue = cv::Scalar() -- 边界的颜色设置,一般默认是0imshow("包含书本目标的翘曲图像", Src);imshow("经过选中书本目标并透射变换后的校正图像", ResultIMG);waitKey(0);
}

效果

鼠标点击选取角点版本

struct userdata {Mat im;vector<Point2f> points;
};void mouseHandler(int event, int x, int y, int flags, void* data_ptr)
{if (event == EVENT_LBUTTONDOWN){userdata* data = ((userdata*)data_ptr);circle(data->im, Point(x, y), 3, Scalar(0, 0, 255), 5, CV_AA);imshow("Image", data->im);if (data->points.size() < 4){data->points.push_back(Point2f(x, y));}}
}void WarpPerspective(int,void*)
{Mat im_src = imread("D:/实验台/机器视觉/测试图片/书本1.jpg");// Destination image. The aspect ratio of the book is 3/4Size size(300, 400);Mat im_dst = Mat::zeros(size, CV_8UC3);// Create a vector of destination points.vector<Point2f> pts_dst;pts_dst.push_back(Point2f(0, 0));pts_dst.push_back(Point2f(size.width - 1, 0));pts_dst.push_back(Point2f(size.width - 1, size.height - 1));pts_dst.push_back(Point2f(0, size.height - 1));// Set data for mouse eventMat im_temp = im_src.clone();userdata data;data.im = im_temp;cout << "Click on the four corners of the book -- top left first and" << endl<< "bottom left last -- and then hit ENTER" << endl;// Show image and wait for 4 clicks.imshow("Image", im_temp);// Set the callback function for any mouse eventsetMouseCallback("Image", mouseHandler, &data);waitKey(0);// Calculate the homographyMat h = findHomography(data.points, pts_dst);// Warp source image to destinationwarpPerspective(im_src, im_dst, h, size);// Show imageimshow("Image", im_dst);waitKey(0);
}

open cv平面对象检测及翘曲图像校正-基于FLANN的特征检测和透视变换相关推荐

  1. 视觉深度估计的Pseudo-LiDAR:弥合自动驾驶3D对象检测中的差距(CVPR2019)

    摘要 3D对象检测是自动驾驶中的一项基本任务.只要从精确但昂贵的LiDAR技术中获得3D输入数据,最新技术就可以以高度准确的检测率获得优势.迄今为止,基于廉价的单目或立体图像数据的方法导致精度大大降低 ...

  2. 深度学习和目标检测系列教程 2-300:小试牛刀,使用 ImageAI 进行对象检测

    @Author:Runsen 对象检测是一种属于更广泛的计算机视觉领域的技术.它处理识别和跟踪图像和视频中存在的对象.目标检测有多种应用,如人脸检测.车辆检测.行人计数.自动驾驶汽车.安全系统等.Im ...

  3. 将ONNX对象检测模型转换为iOS Core ML(一)

    目录 介绍 使用YOLO进行物体检测 寻找正确的模型 将ONNX转换为Core ML 下一步 总目录 将ONNX对象检测模型转换为iOS Core ML(一) 解码Core ML YOLO对象检测器( ...

  4. 开源代码MatrixNets:用于对象检测的新的比例和长宽比感知体系结构

    今天我们介绍MatrixNets(xNets),这是一种用于对象检测的新的深层体系结构.xNets将具有相似大小和高宽比的对象映射到许多专门的层中,从而使xNets可以提供可感知比例和高宽比的体系结构 ...

  5. Dataset:数据集集合(CV方向数据集)-常见的计算机视觉图像数据集大集合包括表面缺陷检测数据集(持续更新)

    Dataset:数据集集合(CV方向数据集)-常见的计算机视觉图像数据集大集合包括表面缺陷检测数据集(建议收藏,持续更新) 目录 CV常用数据集平台集合 Mendeley Data CAISA-Web ...

  6. YOLOV:图像对象检测器在视频对象检测方面表现也很不错

    前言 与传统的两段pipeline不同,论文提出了在一段检测之后再进行区域级的选择,避免了处理大量低质量的候选区域.此外,还构建了一个新的模块来评估目标帧与参考帧之间的关系,并指导聚合. 作者进行了大 ...

  7. CV之FD之HOG:图像检测之基于HOG算法、简介、代码实现(计算图像相似度)之详细攻略

    CV之FD之HOG:图像检测之基于HOG算法.简介.代码实现(计算图像相似度)之详细攻略 图像检测之基于HOG算法.简介.代码实现(计算图像相似度)之详细攻略 相关文章:CV之FD之HOG:图像检测之 ...

  8. OpenCV使用cv :: CascadeClassifier类检测视频流中的对象的实例(附完整代码)

    Open使用cv :: CascadeClassifier类检测视频流中的对象的实例 OpenCV使用cv :: CascadeClassifier类检测视频流中的对象的实例 OpenCV使用cv : ...

  9. AI队列长度检测:使用YOLO进行图像中的对象检测

    目录 YOLO简介 创建和加载模型 预处理输入 获取边界框 下一步是什么? 下载源219 MB 在本系列的前几篇文章中,我们从头开始实现了对象检测.我们观察到从头训练模型需要大量的计算资源和时间.这些 ...

最新文章

  1. ps aux参数说明
  2. seaborn使用FacetGrid函数可视化山脊图(Ridgeline Plot with Seaborn)
  3. 首发:友盟2015年Q2、Q3中国移动互联网趋势报告
  4. 【电子信息复试】考研复试常考问题——数据库
  5. 应用深度学习(台大陈蕴侬李宏毅) Part1
  6. Spring Boot 开源软件都有哪些?
  7. 【Flink】RuntimeException: Row arity of from does not match serializers
  8. 北大计算机科学与技术怎么样,国内高校计算机科学与技术学科排名,浙大表现亮眼,北大荣登榜首...
  9. Stanford机器学习---第十一讲.异常检测
  10. 构建之法:第八次心得
  11. DolbyAudio访问杜比音效驱动程序时发生问题,请重新启动计算机或......
  12. uReport2报表工具的基础使用及注意事项
  13. Libmodbus 移植
  14. 虚拟机VM安装win7遇到的问题及解决方法
  15. ibm的odm使用_使用IBM ODM API生成规则工件
  16. 百度快照出问题投诉有没有用?
  17. JAVAapi—数据库连接
  18. Linux文件裸写,linux环境先mkfs后写裸盘
  19. 正则表达式(判断中文,判断英文字母、下划线、数字)
  20. FTPserver 配置

热门文章

  1. CentOs6.5 详细安装步骤
  2. EndNote的安装与使用
  3. 特斯拉进化论:舍命狂奔背后的生存哲学
  4. C语言学习路线,思维脑图,学单片机的一定要知道
  5. Deskpool云教室(云课堂)系列化配置
  6. 输出一个小游戏——三子棋
  7. 商城项目15_采购需求、合并采购单、领取采购单、完成采购、仓库流程图
  8. 手把手教你做智能手环
  9. 2022年Github学生包白嫖!
  10. 计算机准备计划,你为计算机考试做好准备了吗?敬业签便签帮你制定详细复习计划...