29447945

  • 2020-09-21
  • 发表了主题帖: 【树莓派4B测评】+OPENCV 简单车牌定位

    近年来,汽车车牌识别(License Plate Recognition)已经越来越受到人们的重视。特别是在智能交通系统中,汽车牌照识别发挥了巨大的作用。汽车牌照的自动识别技术是把处理图像的方法与计算机的软件技术相连接在一起,以准确识别出车牌牌照的字符为目的,将识别出的数据传送至交通实时管理系统,以最终实现交通监管的功能。在车牌自动识别系统中,从汽车图像的获取到车牌字符处理是一个复杂的过程,主要分为四个阶段:图像获取、车牌定位、字符分割以及字符识别。   灰度化: 在车牌识别中我们需要将图像转化为灰度图像,这样有利于后续步骤的开展,如Soble算子只能作用于灰度图像。 灰度化,在RGB模型中,如果R=G=B时,则彩色表示一种灰度颜色,其中R=G=B的值叫灰度值,因此,灰度图像每个像素只需一个字节存放灰度值(又称强度值、亮度值),灰度范围为0-255。 Opencv中函数 void cvtColor(InputArray src,  OutputArray dst,  int code,  int dstCn=0 ) 参数详解:  src:输入图像:8位无符号的16位无符号(cv_16uc…)或单精度浮点。  dst:的大小和深度src. code:输出图像颜色空间转换的代码。 dstCn:目标图像中的信道数;如果参数为0,则从SRC和代码自动导出信道的数目。 Mat Grayscale(Mat &img) { Mat out; cvtColor(img, out, COLOR_RGB2GRAY); return out; }   高斯模糊: 车牌识别中利用高斯模糊将图片平滑化,去除干扰的噪声对后续图像处理的影响。 高斯模糊(GaussianBlur()),也叫高斯平滑。 周边像素的平均值,所谓"模糊",可以理解成每一个像素都取周边像素的平均值。 Mat Gaussian(Mat &img) { Mat out; GaussianBlur(img, out, Size(3, 3), 0, 0, BORDER_DEFAULT); return out; } Sobel算子(X方向): 车牌定位的核心算法,水平方向上的边缘检测,检测出车牌区域。 主要用于获得数字图像的一阶梯度,常见的应用和物理意义是边缘检测。在技术上,它是一个离散的一阶差分算子,用来计算图像亮度函数的一阶梯度之近似值。在图像的任何一点使用此算子,将会产生该点对应的梯度矢量或是其法矢量。 该算子包含两组3x3的矩阵,分别为横向及纵向,将之与图像作平面卷积,即可分别得出横向及纵向的亮度差分近似值。如果以A代表原始图像,Gx及Gy分别代表经横向及纵向边缘检测的图像,其公式如下: 图像的每一个像素的横向及纵向梯度近似值可用以下的公式结合,来计算梯度的大小。 可用以下公式计算梯度方向。 在以上例子中,如果以上的角度Θ等于零,即代表图像该处拥有纵向边缘,左方较右方暗。   OpenCV中函数: void Sobel(InputArray src, OutputArray dst, int ddepth, int xorder, int yorder, int ksize=3, double scale=1, double delta=0, int borderType=BORDER_DEFAULT ) 参数: src: 源图像。 dst:相同大小和相同数量的通道的目标图像。 ddepth:目标图像的深度。 xorder:阶导数的X. yorder:阶导数的Y. ksize:扩展Sobel算子–大小。它必须是1, 3, 5,或者7。 scale:计算衍生值的可选刻度因子。默认情况下,不应用缩放。看到getderivkernels()详情。 delta :可选的delta值,在将它们存储在DST之前添加到结果中。 bordertype:像素外推方法。 convertScaleAbs()——先缩放元素再取绝对值,最后转换格式为8bit型。 Mat Sobel(Mat &img) { Mat out; Mat grad_x, grad_y; Mat abs_grad_x, abs_grad_y; int scale = 1; int delta = 0; int ddepth = CV_16S; int th = 100; Sobel( img, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT ); //Scharr( grad_x, grad_x, ddepth, 1, 0, scale, delta, BORDER_DEFAULT ); //Sobel( img, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT ); //Scharr( grad_y, grad_y, ddepth, 0, 1, scale, delta, BORDER_DEFAULT ); convertScaleAbs( grad_x, out ); // convertScaleAbs( grad_y, abs_grad_y ); // addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, out ); // Mat out; // Mat grad_x, grad_y; // Mat abs_grad_x, abs_grad_y; //X方向 //Sobel(img, grad_x, CV_16S, 1, 0, 3, 1, 1, BORDER_DEFAULT); //convertScaleAbs(grad_x, abs_grad_x); // Sobel(img, grad_x, CV_16S, 1, 0, 1, 3, 1, BORDER_DEFAULT); // convertScaleAbs(img, out); //Y方向 //Sobel(img, grad_y, CV_16S, 0, 1, 3, 1, 1, BORDER_DEFAULT); //convertScaleAbs(grad_y, abs_grad_y); //convertScaleAbs(img, out); //合并 //addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, out); return out; } 二值化: 进一步对图像进行处理,强化目标区域,弱化背景。 图像的二值化,就是将图像上的像素点的灰度值设置为0或255,也就是将整个图像呈现出明显的只有黑和白的视觉效果。 OpenCV中函数 double threshold(InputArray src, OutputArray dst, double thresh, double maxVal, int thresholdType) 参数: src:源阵列(单通道,32位浮点8位)。 dst:相同大小和类型的目标数组。 thresh:门限阈值。 Maxval:最大值使用的thresh_binary和thresh_binary_inv阈值类型。 thresholdtype:阈值型,如下。  THRESH_BINARY  当前点值大于阈值时,取Maxval,也就是第四个参数,下面再不说明,否则设置为0  THRESH_BINARY_INV 当前点值大于阈值时,设置为0,否则设置为Maxval  THRESH_TRUNC 当前点值大于阈值时,设置为阈值,否则不改变  THRESH_TOZERO 当前点值大于阈值时,不改变,否则设置为0  THRESH_TOZERO_INV  当前点值大于阈值时,设置为0,否则不改变 Mat TwoValued(Mat &img) { Mat out; threshold(img, out, 0, 255, THRESH_BINARY|THRESH_OTSU); //threshold(img, out, 100, 255, CV_THRESH_BINARY); return out; } 闭操作: 闭操作可以将目标区域连成一个整体,便于后续轮廓的提取。 闭操作可使轮廓线更光滑,但与开操作相反的是,闭操作通常消弥狭窄的间断和长细的鸿沟,消除小的空洞,并填补轮廓线中的断裂。 使用结构元素B对集合A进行闭操作,定义为 这个公式表明,使用结构元素B对集合A的闭操作就是用B对A进行膨胀,然后用B对结果进行腐蚀。   OpenCV中函数 void morphologyEx(InputArray src, OutputArray dst, int op, InputArray element, Point anchor=Point(-1,-1), int iterations=1, int borderType=BORDER_CONSTANT, const Scalar& borderValue=morphologyDefaultBorderValue() ) 参数: src:源图像。 dst:相同大小和类型的目标图像。 element:内核类型    用getStructuringElement函数得到。 OP: 可以是以下形式之一的形态学操作的类型: morph_open -开启操作 morph_close -闭合操作 morph_gradient -形态学梯度 morph_tophat“顶帽” morph_blackhat -“黑帽” iterations:侵蚀和膨胀的次数被应用。 bordertype–像素外推方法。 bordervalue–边界值在一个恒定的边界情况。默认值有特殊含义。 关注前4个参数即可,后面用默认参数。 Mat Close(Mat &img) { Mat out; //Mat element(5, 5, CV_8U, cv::Scalar(1)); Mat element = getStructuringElement(MORPH_RECT, Size(17, 5)); morphologyEx(img, out, cv::MORPH_CLOSE, element); return out; } 取轮廓: 将前面处理的车牌目标区域提取出来。 相关函数: 查找轮廓: void findContours(InputOutputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int mode, int method, Point offset=Point()) image: 输入的 8-比特、单通道图像. 非零元素被当成 1, 0 象素值保留为 0 - 从而图像被看成二值的。为了从灰度图像中得到这样的二值图像,可以使用 cvThreshold, cvAdaptiveThreshold 或 cvCanny. 本函数改变输入图像内容。  storage :得到的轮廓的存储容器  first_contour :输出参数:包含第一个输出轮廓的指针  header_size :如果 method=CV_CHAIN_CODE,则序列头的大小 >=sizeof(CvChain),否则 >=sizeof(CvContour) .  mode : 提取模式.  CV_RETR_EXTERNAL - 只提取最外层的轮廓  CV_RETR_LIST - 提取所有轮廓,并且放置在 list 中  CV_RETR_CCOMP - 提取所有轮廓,并且将其组织为两层的 hierarchy: 顶层为连通域的外围边界,次层为洞的内层边界。  CV_RETR_TREE - 提取所有轮廓,并且重构嵌套轮廓的全部 hierarchy  method : 逼近方法 (对所有节点, 不包括使用内部逼近的 CV_RETR_RUNS).  CV_CHAIN_CODE - Freeman 链码的输出轮廓. 其它方法输出多边形(定点序列).  CV_CHAIN_APPROX_NONE - 将所有点由链码形式翻译(转化)为点序列形式  CV_CHAIN_APPROX_SIMPLE - 压缩水平、垂直和对角分割,即函数只保留末端的象素点;  CV_CHAIN_APPROX_TC89_L1,  CV_CHAIN_APPROX_TC89_KCOS - 应用 Teh-Chin 链逼近算法. CV_LINK_RUNS - 通过连接为 1 的水平碎片使用完全不同的轮廓提取算法。仅有 CV_RETR_LIST 提取模式可以在本方法中应用.  offset : 每一个轮廓点的偏移量. 当轮廓是从图像 ROI 中提取出来的时候,使用偏移量有用,因为可以从整个图像上下文来对轮廓做分析.  函数 cvFindContours 从二值图像中提取轮廓,并且返回提取轮廓的数目。指针 first_contour 的内容由函数填写。它包含第一个最外层轮廓的指针,如果指针为 NULL,则没有检测到轮廓(比如图像是全黑的)。其它轮廓可以从 first_contour 利用 h_next 和 v_next 链接访问到。 在 cvDrawContours 的样例显示如何使用轮廓来进行连通域的检测。轮廓也可以用来做形状分析和对象识别 - 见CVPR2001 教程中的 squares 样例。该教程可以在 SourceForge 网站上找到。  绘制轮廓: void drawContours(InputOutputArray image, InputArrayOfArrays contours, int contourIdx, const Scalar& color, intthickness=1, int lineType=8, InputArray hierarchy=noArray(), int maxLevel=INT_MAX, Point offset=Point() ) void Contour(Mat &img, Mat &out) { RNG rng(12345); // vector< Mat > contours(1000); // vector<Vec4i> hierarchy(1000); vector<vector<Point>> contours; vector<Vec4i> hierarchy; findContours(img, contours, hierarchy, 3, 2, Point(0, 0)); // return ; vector< vector<Point> >::iterator itc = contours.begin(); vector<RotatedRect> rects; int t = 0; while (itc != contours.end()) { //Create bounding rect of object RotatedRect mr = minAreaRect(Mat(*itc)); //large the rect for more if (!verifySizes(mr)) { itc = contours.erase(itc); } else { ++itc; rects.push_back(mr); } } cv::Mat result; img.copyTo(result); for (int i = 0; i< contours.size(); i++) { drawContours(result, contours, i, Scalar(0, 0, 255), 2, 8, vector<Vec4i>(), 0, Point()); //drawContours(result, contours, i, Scalar(255), 2); } //imshow("画轮廓", out); for (int i = 0; i < rects.size(); i++) { circle(result, rects.center, 3, Scalar(0, 255, 0), -1); float minSize = (rects.size.width < rects.size.height) ? rects.size.width : rects.size.height; //minSize = minSize - minSize*0.5; srand(time(NULL)); Mat mask; mask.create(out.rows + 2, out.cols + 2, CV_8UC1); mask = Scalar::all(0); int loDiff = 30; int upDiff = 30; int connectivity = 4; int newMaskVal = 255; int NumSeeds = 10; Rect ccomp; int flags = connectivity + (newMaskVal << 8) + (1 << 16) + (1 << 17); for (int j = 0; j < NumSeeds; j++) { Point seed; seed.x = rects.center.x + rand() % (int)minSize - (minSize / 2); seed.y = rects.center.y + rand() % (int)minSize - (minSize / 2); circle(result, seed, 1, Scalar(0, 255, 255), -1); int area = floodFill(out, mask, seed, Scalar(255, 0, 0), &ccomp, Scalar(loDiff, loDiff, loDiff), Scalar(upDiff, upDiff, upDiff), flags); } //imshow("漫水填充", mask); vector<Point> pointsInterest; Mat_<uchar>::iterator itMask = mask.begin<uchar>(); Mat_<uchar>::iterator end = mask.end<uchar>(); for (; itMask != end; ++itMask) if (*itMask == 255) pointsInterest.push_back(itMask.pos()); RotatedRect minRect = minAreaRect(pointsInterest); if (verifySizes(minRect)) { // rotated rectangle drawing Point2f rect_points[4]; minRect.points(rect_points); for (int j = 0; j < 4; j++) line(result, rect_points[j], rect_points[(j + 1) % 4], Scalar(0, 0, 255), 1, 8); //Get rotation matrix float r = (float)minRect.size.width / (float)minRect.size.height; float angle = minRect.angle; if (r < 1) angle = 90 + angle; Mat rotmat = getRotationMatrix2D(minRect.center, angle, 1); //Create and rotate image Mat img_rotated; warpAffine(out, img_rotated, rotmat, out.size(), 2);//实现旋转 //Crop image Size rect_size = minRect.size; if (r < 1) swap(rect_size.width, rect_size.height); Mat img_crop; getRectSubPix(img_rotated, rect_size, minRect.center, img_crop); Mat resultResized; resultResized.create(33, 144, CV_8UC3); resize(img_crop, resultResized, resultResized.size(), 0, 0, INTER_CUBIC);; ////Equalize croped image Mat grayResult; cvtColor(resultResized, grayResult, COLOR_BGR2GRAY);// CV_RGB2GRAY blur(grayResult, grayResult, Size(3, 3)); grayResult = histeq(grayResult); if (1) { stringstream ss(stringstream::in | stringstream::out); ss << "haha" << "_" << i << ".jpg"; imwrite(ss.str(), grayResult); } } } }   最后主函数如下: int main() { Mat img; Mat out; //Mat result; //载入图片 img = imread("car.jpg");//, CV_LOAD_IMAGE_GRAYSCALE); img.copyTo(out); //imshow ("原始图", img); img = Grayscale(img); imshow("灰度化", img); img = Gaussian(img); imshow ("高斯模糊", img); img = Sobel(img); imshow("Sobel_X", img); img = TwoValued(img); imshow("二值化", img); img = Close(img); imshow("闭操作", img); Contour(img, out); waitKey(0); destroyAllWindows(); return 0; } 然后编写cmake文件: cmake_minimum_required(VERSION 2.8) project( test ) find_package( OpenCV REQUIRED ) add_executable( test test.cpp ) target_link_libraries( test ${OpenCV_LIBS} ) 最后camke 和make pi@raspberrypi:~/Public/OPENCV/program/Image_Identification $ cmake . -- The C compiler identification is GNU 8.3.0 -- The CXX compiler identification is GNU 8.3.0 -- Check for working C compiler: /usr/bin/cc -- Check for working C compiler: /usr/bin/cc -- works -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Detecting C compile features -- Detecting C compile features - done -- Check for working CXX compiler: /usr/bin/c++ -- Check for working CXX compiler: /usr/bin/c++ -- works -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Detecting CXX compile features -- Detecting CXX compile features - done -- Found OpenCV: /usr/local (found version "4.4.0") -- Configuring done -- Generating done -- Build files have been written to: /home/pi/Public/OPENCV/program/Image_Identification pi@raspberrypi:~/Public/OPENCV/program/Image_Identification $ make Scanning dependencies of target test [ 50%] Building CXX object CMakeFiles/test.dir/test.cpp.o [100%] Linking CXX executable test [100%] Built target test pi@raspberrypi:~/Public/OPENCV/program/Image_Identification $ 运行之后界面出现如下窗口: 然后在工程目录下可以看到多了3个图片: 打开图片,可以看到已经定位到了车牌了: 后续就需要把数字分离并识别了 附上代码:

  • 发表了主题帖: 【树莓派4B测评】+搭建OPENCV环境

    OpenCV是一个基于BSD许可(开源)发行的跨平台计算机视觉和机器学习软件库,可以运行在Linux、Windows、Android和Mac OS操作系统上。 它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了Python、Ruby、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。 今天在树莓派上搭建OPENCV环境: 1.安装numpy sudo pip3 instal 2. 安装OpenCV所需的依赖 sudo apt-get install build-essential git cmake pkg-config -y sudo apt-get install libjpeg8-dev -y sudo apt-get install libtiff5-dev -y sudo apt-get install libjasper-dev -y sudo apt-get install libpng12-dev -y sudo apt-get install libavcodec-dev libavformat-dev libswscale-dev libv4l-dev -y sudo apt-get install libgtk2.0-dev -y sudo apt-get install libatlas-base-dev gfortran -y 3.下载OpenCV 可以github上下载,也可以下载压缩包; 本次安装的OpenCV版本为OpenCV 4.4.0,官方链接地址 需要下载包括OpenCV与OpenCV_Contrib两个仓库 OpenCV_4.4.0仓库:Github地址 4.配置cmake;Cmake是一款跨平台的编译工具,经过配置,可输出适配于树莓派平台的Makefile 在opencv-4.4.0目录下新建一个build文件夹 然后进入文件夹 然后camke cd/opencv-4.4.0 mkdir build cd build cmake . 5.没有出错,直接make 注意:make编译时间比较长,一般编译时间在5小时左右。 6.安装 sudo make insall 7.测试安装; 首先进入源码的示例文件夹中:opencv-4.4.0/samples/cpp/example_cmake 然后cmake 和make  pi@raspberrypi:~/Public/opencv-4.4.0/samples/cpp/example_cmake $ sudo cmake . -- The C compiler identification is GNU 8.3.0 -- The CXX compiler identification is GNU 8.3.0 -- Check for working C compiler: /usr/bin/cc -- Check for working C compiler: /usr/bin/cc -- works -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Detecting C compile features -- Detecting C compile features - done -- Check for working CXX compiler: /usr/bin/c++ -- Check for working CXX compiler: /usr/bin/c++ -- works -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Detecting CXX compile features -- Detecting CXX compile features - done -- Found OpenCV: /usr/local (found version "4.4.0") -- OpenCV library status: -- config: /usr/local/lib/cmake/opencv4 -- version: 4.4.0 -- libraries: opencv_calib3d;opencv_core;opencv_dnn;opencv_features2d;opencv_flann;opencv_gapi;opencv_highgui;opencv_imgcodecs;opencv_imgproc;opencv_ml;opencv_objdetect;opencv_photo;opencv_stitching;opencv_video;opencv_videoio -- include path: /usr/local/include/opencv4 -- Configuring done -- Generating done -- Build files have been written to: /home/pi/Public/opencv-4.4.0/samples/cpp/example_cmake pi@raspberrypi:~/Public/opencv-4.4.0/samples/cpp/example_cmake $ sudo make Scanning dependencies of target opencv_example [ 50%] Building CXX object CMakeFiles/opencv_example.dir/example.cpp.o [100%] Linking CXX executable opencv_example [100%] Built target opencv_example pi@raspberrypi:~/Public/opencv-4.4.0/samples/cpp/example_cmake $ sudo ./opencv_example 最后执行后弹出摄像头的界面,说明安装没有问题,如下图:

  • 2020-09-11
  • 回复了主题帖: 【十一自驾游】——有山有水线路,求推荐

    btty038 发表于 2020-9-10 10:26 去过但是不是自驾游    属于跟团的那种     从丽江  大理   来 ...
    跟团真的只是打卡,要玩的开心还是需要自己攻略玩

  • 回复了主题帖: 【十一自驾游】——有山有水线路,求推荐

    maoshen 发表于 2020-9-11 14:26 上海的表示出上海要报备,,现在是特殊时期,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
    还这么严吗?感觉国内形势已经没啥问题了呀

  • 回复了主题帖: soso 带你逛逛华为开发者大会2020(海量美图)

    昨天看了下在线直播,为华为点赞

  • 2020-09-10
  • 回复了主题帖: 【十一自驾游】——有山有水线路,求推荐

    chunyang 发表于 2020-9-9 16:56 四驱越野车的话,技术和身体没问题,倒是可以川藏—青藏—甘陕一圈下来。轿车的话,可以考虑湖北 ...
    川藏线确实想走一走

  • 回复了主题帖: 【十一自驾游】——有山有水线路,求推荐

    chunyang 发表于 2020-9-9 17:00 也不错,不过更适合的季节反而是五一、端午期间。
    确实

  • 回复了主题帖: 【十一自驾游】——有山有水线路,求推荐

    btty038 发表于 2020-9-9 21:15 那个苍山洱海旁  符合有山有水     车子基本都可以
    苍山洱海可以有,有没有去过,有啥攻略吗?

  • 2020-09-09
  • 回复了主题帖: 【十一自驾游】——有山有水线路,求推荐

    reno1986 发表于 2020-9-9 16:34 自驾大西北
    可以有,青海湖环线怎么样?

  • 回复了主题帖: 【十一自驾游】——有山有水线路,求推荐

    freebsder 发表于 2020-9-9 15:06 湖北。全境5A免费
    这个确实不错,不过怕人太多,看人时间多了,冷门一点的线路

  • 发表了主题帖: 【十一自驾游】——有山有水线路,求推荐

    十一国庆快到了,8天假期准备出去自驾游,看山看水看雪看祖国大好山河,求大家推荐,出发地:成都

  • 加入了学习《趣味电子技术史话:通信技术发展史》,观看 最早的电的放大器

  • 加入了学习《基于 C2000 的数字车载电源控制系统》,观看 TI C2000 在电动车辆上的数字电源应用 - 系统微控制器架构

  • 加入了学习《基于 C2000 的数字车载电源控制系统》,观看 TI C2000 在电动车辆上的数字电源应用 - 介绍

  • 加入了学习《TI DLP? Labs - 汽车:抬头显示》,观看 1.1 DLP 技术在增强现实抬头显示器应用中的优势

  • 2020-09-01
  • 加入了学习《Digi-Key :图形算法在深度学习等应用中的加速手段》,观看 图形算法在深度学习中的加速应用

  • 2020-08-31
  • 发表了主题帖: 【树莓派4B测评】+搭建文件服务器

    本帖最后由 29447945 于 2020-8-31 19:55 编辑 我们要使用连接下载服务器的文件,这里使用openresty搭建一个文件服务器; 首先我们需要下载openresty,官网下载:https://openresty.org/cn/download.html 下载本地后,解压文件 tar zvxf openresty-1.17.8.2.tar.gz  解压缩后,到解压目录中安装; sudo  ./configure sudo make sudo make install 然后配置文件 sudo vim /usr/local/openresty/nginx/conf/nginx.conf  在http -> server 字段下添加 location /files {      autoindex on; # 开启索引功能     autoindex_exact_size off; # 关闭计算文件确切大小(单位bytes),只显示大概大小(单位kb、mb、gb)       autoindex_localtime on; # 显示本机时间而非 GMT 时间       alias /var/files;   # 显示的根索引目录 } 如下图 然后更改共享目录的权限 /home/pi/Public  然后运行 sudo /usr/local/openresty/bin/openresty  如果更改了配置文件,则重新运行一下 sudo /usr/local/openresty/bin/openresty  -s relaod 运行后,使用浏览器测试一下; 浏览器可以访问我的共享目录中的文件了。

  • 发表了主题帖: 【树莓派4B测评】+TCP服务器和HTTP通信

    今天使用树莓派搭建一个TCP服务器,使用HTTP通信,话不多说,直接开始; 首先检查树莓派是都安装curl库; 输入命令:curl www.baidu.com 可以看到是有curl库的,如果没有也可以自己装一下; 然后就是建立TCP服务,通过socket通信完成;具体过程:建立socket->绑定端口和IP->Listen->等待客户端连接->断开连接;如果是客户端则是:建立socket->绑定端口和IP->连接服务器->断开连接; 代码如下: int main(int argc,char **argv) { const int port = 9689;//listen port int listenfd=Socket(AF_INET,SOCK_STREAM,0); struct sockaddr_in serverAddr; serverAddr.sin_family=AF_INET; serverAddr.sin_addr.s_addr=INADDR_ANY; serverAddr.sin_port=htons(port); Bind(listenfd,(struct sockaddr*)&serverAddr,sizeof(serverAddr)); Listen(listenfd,5); while(true) { handleAccept(listenfd); } } int Socket(int family , int type,int protocol) { int n; if ( (n = socket(family, type, protocol)) < 0) { printf("socket error\r\n"); return -1; } return(n); } void Bind(int fd, const struct sockaddr *sa, socklen_t salen) { if (bind(fd, sa, salen) < 0) { printf("bind error\r\n"); exit(-1); } } void Listen(int fd, int backlog) { char *ptr; /*4can override 2nd argument with environment variable */ if ( (ptr = getenv("LISTENQ")) != NULL) backlog = atoi(ptr); if (listen(fd, backlog) < 0) { printf("listen error\r\n"); return ; } } int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr) { int n; again: if ( (n = accept(fd, sa, salenptr)) < 0) { #ifdef EPROTO if (errno == EPROTO || errno == ECONNABORTED) #else if (errno == ECONNABORTED) #endif goto again; else { printf("accept error\r\n"); return -1; } } return(n); } void handleAccept(int listenfd) { sockaddr_in clientAddr; socklen_t clientLen=sizeof(clientAddr); int connfd=Accept(listenfd,(sockaddr *)&clientAddr,&clientLen); handleHttp(connfd); close(connfd); } 我这里做了一个简单的http例程,就是访问连接服务器后,回复一个网页,代码如下: void handleHttp(int connfd) { if(getRequest(connfd)<0) { perror("http request get error"); exit(-1); } } int getRequest(int socket) { int msgLen=0; char send_data[BUFFER_SIZE]; char buffer[BUFFER_SIZE]; memset (buffer,'\0', BUFFER_SIZE); if ((msgLen = recv(socket, buffer, BUFFER_SIZE, 0)) == -1) { printf("Error handling incoming request"); return -1; } else { printf("recv:\n%s\n",buffer); } memset (send_data,'\0', BUFFER_SIZE); //create_objects(send_data); stringstream ss; ss<<buffer; string method; ss>>method; string uri; ss>>uri; string version; ss>>version; // string contentType("text/html"); string content("<html><head><title>simple httpserver</title></head><h1>hello eeworld</h1></body></html>"); string contentSize(std::to_string(content.size())); string head("\r\nHTTP/1.1 "); string statusCode("200 OK"); string ContentType("\r\nContent-Type: "); string ServerHead("\r\nServer: localhost"); string ContentLength("\r\nContent-Length: "); string Date("\r\nDate: "); string Newline("\r\n"); time_t rawtime; time(&rawtime); string message; message+=head; message+=statusCode; message+=ContentType; message+=contentType; message+=ServerHead; message+=ContentLength; message+=contentSize; message+=Date; message+=(string)ctime(&rawtime); message+=Newline; int messageLength=message.size(); int n; n=send(socket,message.c_str(),messageLength,0); n=send(socket,content.c_str(),content.size(),0); return n; } 然后编译一下: g++ http_test.cpp -o http 在运行./http  服务运行后,我们用浏览器打开试下 打印了我们设置的内容; 我们在使用curl测试一下: curl 192.168.31.235:9689

  • 2020-08-28
  • 回复了主题帖: led点阵屏,想问一下各位大佬,为什么我只点亮一个灯,它一整排都亮了

    一般来说都是你程序问题,网上有很多这种屏的例子,自己改吧改吧就能亮了。

  • 回复了主题帖: 龙芯决定放弃所有美国技术,做真正的纯国产指令集

    期待中国电子产业改头换面

统计信息

已有129人来访过

  • 芯币:751
  • 好友:2
  • 主题:32
  • 回复:416
  • 课时:1
  • 资源:3

留言

你需要登录后才可以留言 登录 | 注册


现在还没有留言