• 基于opencv3.0和zbar下条形码和二维码的识别与解码


    其中对条码与二维码的识别分为以下4个步骤

    1. 利用opencv和Zbar(或者Zxing)对标准的条形码图片(即没有多余背景干扰,且图片没有倾斜)进行解码,将解码信息显示出来,并与原始信息对比。

    2. 利用opencv和Zbar(或者Zxing)对标准的QR二维码图片(即没有多余背景干扰,且图片没有倾斜)进行解码,将解码信息显示出来,并与原始信息对比。

    3. 对非标准条形码,进行定位,然后用Zbar(或者Zxing)解码显示。

    4. 对非标准的QR二维码图片,进行定位,然后用Zbar(或者Zxing)解码显示。

    1. 利用opencv和Zbar(或者Zxing)对标准的条形码图片(即没有多余背景干扰,且图片没有倾斜)进行解码,将解码信息显示出来,并与原始信息对比。

    2. 利用opencv和Zbar(或者Zxing)对标准的QR二维码图片(即没有多余背景干扰,且图片没有倾斜)进行解码,将解码信息显示出来,并与原始信息对比。

    这两部对于zbar可以一并操作。

    操作步骤主要分为两部分:A.原图进行灰度转化,B.送入Zbar扫描仪进行扫描(调用ImageScanner)

    源码如下:

     1 /******************************************************
     2 函数名称: Dis_Barcode
     3 函数功能: 识别条形码和二维码
     4 传入参数:
     5 返 回 值:
     6 建立时间: 2018-05-19
     7 修改时间:
     8 建 立 人: 
     9 修 改 人:
    10 其它说明:这里是借鉴其他人的代码:
    11 原文链接:https://www.cnblogs.com/dengxiaojun/p/5278679.html
    12 以下代码是经过改动的
    13 ******************************************************/
    14 void MyClass::Dis_code(Mat image){
    15     Mat imageGray;  // 所转化成的灰度图像 
    16     //定义一个扫描仪  
    17     ImageScanner scanner;
    18     scanner.set_config(ZBAR_NONE, ZBAR_CFG_ENABLE, 1);
    19 
    20     cvtColor(image, imageGray, CV_RGB2GRAY);
    21     imshow("灰度图", imageGray);
    22     // 获取所摄取图像的长和宽  
    23     int width = imageGray.cols;
    24     int height = imageGray.rows;
    25     // 在Zbar中进行扫描时候,需要将OpenCV中的Mat类型转换为(uchar *)类型,raw中存放的是图像的地址;对应的图像需要转成Zbar中对应的图像zbar::Image  
    26     uchar *raw = (uchar *)imageGray.data;
    27     Image imageZbar(width, height, "Y800", raw, width * height);
    28     // 扫描相应的图像imageZbar(imageZbar是zbar::Image类型,存储着读入的图像)  
    29     scanner.scan(imageZbar); //扫描条码      
    30     Image::SymbolIterator symbol = imageZbar.symbol_begin();
    31     if (imageZbar.symbol_begin() == imageZbar.symbol_end())
    32     {
    33         cout << "查询条码失败,请检查图片!" << endl;
    34     }
    35     for (; symbol != imageZbar.symbol_end(); ++symbol)
    36     {
    37         cout << "类型:" << endl << symbol->get_type_name() << endl << endl;
    38         cout << "条码:" << endl << symbol->get_data() << endl << endl;
    39     }
    40 
    41     waitKey(); // 等待按下esc键,若需要延时1s则改用waitKey(1000);  
    42 
    43     // 将图像中的数据置为0  
    44     imageZbar.set_data(NULL, 0);
    45     system("pause");
    46 }

    结果如下:

    条形码识别:

    二维码识别:

     

    3. 对非标准条形码,进行定位,然后用Zbar(或者Zxing)解码显示

    在条形码的识别上,根据条形码的特性,我们只关心x轴上的形态。通过x轴的宽度进行确定条码的大小,y轴根据实际提取进行区分

    处理的目标:

    A.消去非码的其他物体图形

    B.划定条码的范围

    C.提取图片的ROI区域(即条码区域)

     总体分为:

    灰度处理-》高斯平滑-》Sobel x—y梯度差-》均值滤波-》二值化-》闭运算-》腐蚀膨胀-》获取ROI

     1 /******************************************************
     2 函数名称: Run
     3 函数功能: 开始
     4 传入参数:
     5 返 回 值:
     6 建立时间: 2018-05-19
     7 修改时间:
     8 建 立 人: 
     9 修 改 人:
    10 其它说明:
    11 ******************************************************/
    12 void MyClass::Run(){
    13     Mat image;
    14     image = getGray(srcimage);//获取灰度图
    15     image = getGass(image);//高斯平滑滤波
    16     image = getSobel(image);//Sobel x—y梯度差
    17     image = getBlur(image);//均值滤波除高频噪声
    18     image = getThold(image);//二值化
    19     image = getBys(image);//闭运算
    20     image = getErode(image);//腐蚀
    21     image = getDilate(image);//膨胀
    22     image = getRect(image, srcimage);//获取ROI
    23     imshow("最后的图", image);
    24     Dis_code(image);
    25     waitKey();
    26 }

    灰度处理(消除颜色干扰)

     1 /******************************************************
     2 函数名称: getGray
     3 函数功能: 灰度处理
     4 传入参数: Mat image
     5 返 回 值:
     6 建立时间: 2018-05-19
     7 修改时间:
     8 建 立 人: 
     9 修 改 人:
    10 其它说明:
    11 ******************************************************/
    12 Mat MyClass::getGray(Mat image, bool show){//show默认false 待定参数法
    13     Mat cimage;
    14     cvtColor(image, cimage, CV_RGBA2GRAY);
    15     if (show)
    16     imshow("灰度图", cimage);
    17     return cimage;
    18 }

    处理结果:

    高斯滤波处理(消除高斯噪声)

     1 /******************************************************
     2 函数名称: getGass
     3 函数功能: 高斯滤波处理
     4 传入参数: Mat image
     5 返 回 值:
     6 建立时间: 2018-05-19
     7 修改时间:
     8 建 立 人: 
     9 修 改 人:
    10 其它说明:
    11 ******************************************************/
    12 Mat MyClass::getGass(Mat image, bool show){
    13     Mat cimage;
    14     GaussianBlur(image, cimage, Size(3, 3), 0);
    15     if (show)
    16     imshow("高斯滤波图", cimage);
    17     return cimage;
    18 }
     

    处理结果:

    Sobel x-y差处理(只考虑x轴,消除y轴不必要信息)

     1 /******************************************************
     2 函数名称: getSobel
     3 函数功能: Sobel处理
     4 传入参数: Mat image
     5 返 回 值:
     6 建立时间: 2018-05-19
     7 修改时间:
     8 建 立 人: 
     9 修 改 人:
    10 其它说明:
    11 ******************************************************/
    12 Mat MyClass::getSobel(Mat image, bool show){
    13     Mat cimageX16s, cimageY16s, imageSobelX, imageSobelY, out;
    14     Sobel(image, cimageX16s, CV_16S, 1, 0, 3, 1, 0, 4);
    15     Sobel(image, cimageY16s, CV_16S, 0, 1, 3, 1, 0, 4);
    16     convertScaleAbs(cimageX16s, imageSobelX, 1, 0);
    17     convertScaleAbs(cimageY16s, imageSobelY, 1, 0);
    18     out = imageSobelX - imageSobelY;
    19     if (show)
    20     imshow("Sobelx-y差 图", out);
    21     return out;
    22 }
     

    处理结果:

    均值滤波处理(消除高频噪声)

     1 /******************************************************
     2 函数名称: getBlur
     3 函数功能: 均值滤波处理
     4 传入参数: Mat image
     5 返 回 值:
     6 建立时间: 2018-05-19
     7 修改时间:
     8 建 立 人: 
     9 修 改 人:
    10 其它说明:
    11  ******************************************************/
    12 Mat MyClass::getBlur(Mat image, bool show){
    13      Mat cimage;
    14      blur(image, cimage, Size(3, 3));
    15      if (show)
    16      imshow("均值滤波图", cimage);
    17      return cimage;
    18  }
     

    处理结果:

    二值化处理(使图像中数据量大为减少,从而能凸显出目标的轮廓)

     1 /******************************************************
     2 函数名称: getThold
     3 函数功能: 二值化处理
     4 传入参数: Mat image
     5 返 回 值:
     6 建立时间: 2018-05-19
     7 修改时间:
     8 建 立 人: 
     9 修 改 人:
    10 其它说明:
    11 ******************************************************/
    12 Mat MyClass::getThold(Mat image, bool show){
    13     Mat cimage;
    14     threshold(image, cimage, 112, 255, CV_THRESH_BINARY);
    15     if (show)
    16     imshow("二值化图", cimage);
    17     return cimage;
    18 }
     

    处理结果:

    闭运算处理(扩大轴之间的间隙)

     1 /******************************************************
     2 函数名称: getBys
     3 函数功能: 闭运算处理
     4 传入参数: Mat image
     5 返 回 值:
     6 建立时间: 2018-05-19
     7 修改时间:
     8 建 立 人: 
     9 修 改 人:
    10 其它说明:
    11 ******************************************************/
    12 Mat MyClass::getBys(Mat image, bool show){
    13     morphologyEx(image, image, MORPH_CLOSE, element);
    14     if (show)
    15     imshow("闭运算图", image);
    16     return image;
    17 }

    处理结果:

    腐蚀膨胀(消去干扰点和合并条码区域)

     1 /******************************************************
     2 函数名称: getErode
     3 函数功能: 腐蚀处理
     4 传入参数: Mat image
     5 返 回 值:
     6 建立时间: 2018-05-19
     7 修改时间:
     8 建 立 人: 
     9 修 改 人:
    10 其它说明:
    11 ******************************************************/
    12 Mat MyClass::getErode(Mat image, bool show){
    13     //Mat cimage;
    14     erode(image, image, element);
    15     if (show)
    16     imshow("腐蚀图", image);
    17     return image;
    18 }
    19 /******************************************************
    20 函数名称: getDilate
    21 函数功能: 膨胀处理
    22 传入参数: Mat image
    23 返 回 值:
    24 建立时间: 2018-05-19
    25 修改时间:
    26 建 立 人: 
    27 修 改 人:
    28 其它说明:
    29 ******************************************************/
    30 Mat MyClass::getDilate(Mat image, bool show){
    31     for (int i = 0; i < 3; i++)
    32         dilate(image, image, element);
    33     if (show)
    34     imshow("膨胀图", image);
    35     return image;
    36 }

    处理结果:

    获取ROI(为Zbar处理作预处理)

     1 /******************************************************
     2 函数名称: getRect
     3 函数功能: 获取码的区域
     4 传入参数: Mat image, Mat simage原图
     5 返 回 值:
     6 建立时间: 2018-05-19
     7 修改时间:
     8 建 立 人: 
     9 修 改 人:
    10 其它说明:借鉴其他人进行改进
    11 ******************************************************/
    12 Mat MyClass::getRect(Mat image, Mat simage, bool show){
    13     vector<vector<Point>> contours;
    14     vector<Vec4i> hiera;
    15     Mat cimage;
    16     findContours(image, contours, hiera, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
    17     vector<float>contourArea;
    18     for (int i = 0; i < contours.size(); i++)
    19     {
    20         contourArea.push_back(cv::contourArea(contours[i]));
    21     }
    22     //找出面积最大的轮廓
    23     double maxValue; Point maxLoc;
    24     minMaxLoc(contourArea, NULL, &maxValue, NULL, &maxLoc);
    25     //计算面积最大的轮廓的最小的外包矩形
    26     RotatedRect minRect = minAreaRect(contours[maxLoc.x]);
    27     //为了防止找错,要检查这个矩形的偏斜角度不能超标
    28     //如果超标,那就是没找到
    29     if (minRect.angle<2.0)
    30     {
    31         //找到了矩形的角度,但是这是一个旋转矩形,所以还要重新获得一个外包最小矩形
    32         Rect myRect = boundingRect(contours[maxLoc.x]);
    33         //把这个矩形在源图像中画出来
    34         //rectangle(srcImage,myRect,Scalar(0,255,255),3,LINE_AA);
    35         //看看显示效果,找的对不对
    36         //imshow(windowNameString,srcImage);
    37         //将扫描的图像裁剪下来,并保存为相应的结果,保留一些X方向的边界,所以对rect进行一定的扩张
    38         myRect.x = myRect.x - (myRect.width / 20);
    39         myRect.width = myRect.width*1.1;
    40         Mat resultImage = Mat(srcimage, myRect);
    41         return resultImage;
    42     }
    43 
    44     for (int i = 0; i<contours.size(); i++)
    45     {
    46         Rect rect = boundingRect((Mat)contours[i]);
    47         //cimage = simage(rect);
    48         rectangle(simage, rect, Scalar(0), 2);
    49         if (show)
    50         imshow("转变图", simage);
    51     }
    52     return simage;
    53 }

    处理结果:

    最后识别处理结果:

     4. 对非标准的QR二维码图片,进行定位,然后用Zbar(或者Zxing)解码显示。

    这里主要参考https://blog.csdn.net/nick123chao/article/details/77573675的博客。不过该博客的处理没有考虑多个识别点时的情况:

    例图:

    本文主要处理去除干扰的识别点的方向进行研究解决。根据二维码特性:

    我们只要找到90°±Δx的角,且夹角两边为最小的边即可。

    找到三个点后,我们需要对齐做旋转处理,旋转的角度如下:

    其中处理的步骤分为:

    灰度处理-》边缘检测-》特征轮廓检测-》提取特征点-》排除干扰点-》绘制直角三角形-》纠正旋转-》提取ROI-》识别

    这里先给效果,后展示代码

    边缘检测:

    特征轮廓检测

    提取特征点-》排除干扰点-》绘制直角三角形

    纠正旋转

    提取ROI

    识别

    源码如下:

      1 /******************************************************
      2 函数名称: QrRun
      3 函数功能: 开始
      4 传入参数:
      5 返 回 值:
      6 建立时间: 2018-05-19
      7 修改时间:
      8 建 立 人: 
      9 修 改 人:
     10 其它说明:
     11 ******************************************************/
     12 void MyClass::QrRun(){
     13     RNG rng(12345);
     14     //imshow("原图", srcimage);
     15     Mat src_all = srcimage.clone();
     16     Mat src_gray;
     17     //灰度处理
     18     src_gray = getBlur(getGray(srcimage));
     19 
     20     Scalar color = Scalar(1, 1, 255);
     21     Mat threshold_output;
     22     vector<vector<Point> > contours, contours2;
     23     vector<Vec4i> hierarchy;
     24     Mat drawing = Mat::zeros(srcimage.size(), CV_8UC3);
     25     Mat drawing2 = Mat::zeros(srcimage.size(), CV_8UC3);
     26     Mat drawingAllContours = Mat::zeros(srcimage.size(), CV_8UC3);
     27 
     28     threshold_output = getThold(src_gray);
     29 
     30     findContours(threshold_output, contours, hierarchy, CV_RETR_TREE, CHAIN_APPROX_NONE, Point(0, 0));
     31 
     32     int c = 0, ic = 0, k = 0, area = 0;
     33     // 边缘检测 
     34     //通过黑色定位角作为父轮廓,有两个子轮廓的特点,筛选出三个定位角  
     35     int parentIdx = -1;
     36     for (int i = 0; i< contours.size(); i++)
     37     {
     38         //画出所以轮廓图  
     39         drawContours(drawingAllContours, contours, parentIdx, CV_RGB(255, 255, 255), 1, 8);
     40         if (hierarchy[i][2] != -1 && ic == 0)
     41         {
     42             parentIdx = i;
     43             ic++;
     44         }
     45         else if (hierarchy[i][2] != -1)
     46         {
     47             ic++;
     48         }
     49         else if (hierarchy[i][2] == -1)
     50         {
     51             ic = 0;
     52             parentIdx = -1;
     53         }
     54         //特征轮廓检测 - 》
     55         //有两个子轮廓  
     56         if (ic >= 2)
     57         {
     58             //保存找到的三个黑色定位角  
     59             contours2.push_back(contours[parentIdx]);
     60             //画出三个黑色定位角的轮廓  
     61             drawContours(drawing, contours, parentIdx, CV_RGB(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), 1, 8);
     62             ic = 0;
     63             parentIdx = -1;
     64         }
     65     }
     66     //提取特征点 
     67     //填充的方式画出黑色定位角的轮廓  
     68     for (int i = 0; i<contours2.size(); i++)
     69         drawContours(drawing2, contours2, i, CV_RGB(rng.uniform(100, 255), rng.uniform(100, 255), rng.uniform(100, 255)), -1, 4, hierarchy[k][2], 0, Point());
     70 
     71     //获取定位角的中心坐标  
     72     vector<Point> pointfind;
     73     for (int i = 0; i<contours2.size(); i++)
     74     {
     75         pointfind.push_back(Center_cal(contours2, i));
     76     }
     77     //排除干扰点
     78     Mat dst;
     79     Point point[3]; double angle; Mat rot_mat;
     80     ///选择合适的点-核心筛选
     81     if (pointfind.size()>3){
     82         double lengthA = 10000000000000000, lengthB = 10000000000000000000;
     83         for (int i = 0; i < pointfind.size(); i++){
     84             for (int j = 0; j < pointfind.size(); j++){
     85                 for (int k = 0; k < pointfind.size(); k++){
     86                     if (i != j&&j != k&&i != k){
     87                         double dxa, dxb,dya,dyb;
     88                         double k1, k2, wa, wb;
     89                         dxa = pointfind[i].x - pointfind[j].x;
     90                         dxb = pointfind[i].x - pointfind[k].x;
     91                         dya = pointfind[i].y - pointfind[j].y;
     92                         dyb = pointfind[i].y - pointfind[k].y;
     93                         if (dxa == 0 || dxb == 0)continue;
     94                         k1 = dya/dxa;
     95                         k2 = dyb/dxb ;
     96                         wa = sqrt(pow(dya, 2) + pow(dya, 2));
     97                         wb = sqrt(pow(dyb, 2) + pow(dxb, 2));
     98                         double anglea = abs(atan(k1) * 180 / CV_PI) + abs(atan(k2) * 180 / CV_PI);
     99                         if (int(anglea)>=85&&int(anglea)<=95&&wa<=lengthA&&wb<=lengthB){
    100                             lengthA = wa;
    101                             lengthB = wb;
    102                             point[0] = pointfind[i];
    103                             point[1] = pointfind[j];
    104                             point[2] = pointfind[k];
    105                         }
    106                     }
    107                 }
    108             }
    109         }
    110     }
    111     else{
    112         for (int i = 0; i < 3; i++){
    113             point[i] = pointfind[i];
    114         }
    115     }
    116     //绘制直角三角形 
    117     //计算轮廓的面积,计算定位角的面积,从而计算出边长  
    118     area = contourArea(contours2[0]);
    119     int area_side = cvRound(sqrt(double(area)));
    120     for (int i = 0; i < 3; i++){
    121         line(drawing2, point[i], point[(i + 1)%3], color, area_side / 2, 8);
    122     }
    123 
    124     //纠正旋转
    125     //判断是否正对
    126     if (!IsCorrect(point)){
    127     //进入修正环节
    128         double angle; Mat rot_mat;
    129         int start = 0;
    130         for (int i = 0; i < 3; i++){
    131             double k1, k2,kk;
    132             k1 = (point[i].y - point[(i + 1) % 3].y) / (point[i].x - point[(i + 1) % 3].x);
    133             k2 = (point[i].y - point[(i + 2) % 3].y) / (point[i].x - point[(i + 2) % 3].x);
    134             kk = k1*k2;
    135             if (k1*k2 <0)
    136                 start = i;
    137         }
    138         double ax, ay, bx, by;
    139         ax = point[(start + 1) % 3].x;
    140         ay = point[(start + 1) % 3].y;
    141         bx = point[(start + 2) % 3].x;
    142         by = point[(start + 2) % 3].y;
    143         Point2f center(abs(ax - bx) / 2, abs(ay -by)/ 2);
    144         double dy = ay - by;
    145         double dx = ax - bx;
    146         double k3 = dy / dx;
    147         angle =atan(k3) * 180 / CV_PI;//转化角度
    148         rot_mat = getRotationMatrix2D(center, angle, 1.0);
    149         
    150         warpAffine(src_all, dst, rot_mat, src_all.size(), 1, 0, 0);//旋转原图查看
    151         warpAffine(drawing2, drawing2, rot_mat, src_all.size(), 1, 0, 0);//旋转连线图
    152         warpAffine(src_all, src_all, rot_mat, src_all.size(), 1, 0, 0);//旋转原图
    153 
    154         namedWindow("Dst");
    155         imshow("Dst", dst);
    156     }
    157 
    158     namedWindow("DrawingAllContours");
    159     imshow("DrawingAllContours", drawingAllContours);
    160 
    161     namedWindow("Drawing2");
    162     imshow("Drawing2", drawing2);
    163 
    164     namedWindow("Drawing");
    165     imshow("Drawing", drawing);
    166 
    167     //提取ROI
    168     //接下来要框出这整个二维码  
    169     Mat gray_all, threshold_output_all;
    170     vector<vector<Point> > contours_all;
    171     vector<Vec4i> hierarchy_all;
    172     cvtColor(drawing2, gray_all, CV_BGR2GRAY);
    173 
    174 
    175     threshold(gray_all, threshold_output_all, 45, 255, THRESH_BINARY);
    176     findContours(threshold_output_all, contours_all, hierarchy_all, RETR_EXTERNAL, CHAIN_APPROX_NONE, Point(0, 0));//RETR_EXTERNAL表示只寻找最外层轮廓  
    177 
    178 
    179     Point2f fourPoint2f[4];
    180     //求最小包围矩形  
    181     RotatedRect rectPoint = minAreaRect(contours_all[1]);//pointfind.size()-3
    182 
    183     //将rectPoint变量中存储的坐标值放到 fourPoint的数组中  
    184     rectPoint.points(fourPoint2f);
    185 
    186     int maxx = 0, maxy = 0, minx = 100000, miny = 100000;
    187     for (int i = 0; i < 4; i++)
    188     {
    189         if (maxx < fourPoint2f[i].x)maxx = fourPoint2f[i].x;
    190         if (maxy < fourPoint2f[i].y)maxy = fourPoint2f[i].y;
    191         if (minx > fourPoint2f[i].x)minx = fourPoint2f[i].x;
    192         if (miny > fourPoint2f[i].y)miny = fourPoint2f[i].y;
    193         line(src_all, fourPoint2f[i % 4], fourPoint2f[(i + 1) % 4]
    194             , Scalar(0), 3);
    195     }
    196     namedWindow("Src_all");
    197     ///边际处理
    198     int set_inter = 5;
    199     while (true)
    200     {
    201         minx -= set_inter;
    202         miny -= set_inter;
    203         maxx += set_inter;
    204         maxy += set_inter;
    205         if (maxx > srcimage.size().width || maxy > srcimage.size().height || minx < 0 || miny < 0){
    206             minx += set_inter;
    207             miny += set_inter;
    208             maxx -= set_inter;
    209             maxy -= set_inter;
    210             set_inter--;
    211         }
    212         else
    213         {
    214             break;
    215         }
    216     }
    217     imshow("Src_all", src_all(Rect(minx, miny, maxx - minx, maxy - miny)));//ROI
    218     Mat fout = src_all(Rect(minx, miny, maxx - minx, maxy - miny));//ROI
    219 
    220     //识别
    221     Dis_code(fout);
    222 
    223     waitKey(0);
    224     destroyAllWindows();
    225 }

    由于在解码上是采用其他人的方法,存在解码问题。(到时候有机会自己再写下)

    ps:目前的zbar不支持中文识别,但是zxing可以。所以借鉴本文的需要改进下识别的模块即可。

    本文的不足之处:

    这里还做了测试,对于旋转180°以上的二维码图片存在可能无法识别的问题。以及码眼为非正方形的也无法识别。

    如需要源码请转移至码云:https://gitee.com/cjqbaba/MediaTest/tree/Code_Find进行源码克隆下载

    如有问题请留言评论。转载请注明出处,谢谢。

  • 相关阅读:
    kafka官方的kafka-server-start.sh不能关闭kafka进程解决办法
    Linux如何切换图形界面和命令行界面
    2019-9-28:渗透测试,基础学习,DNS投毒
    2019-9-28:渗透测试,基础学习,pgp常量,逻辑运算,DNS投毒,笔记
    2019-9-10:渗透测试,基础学习,nmap扫描命令,php基本语法学习,笔记
    2019-9-11:渗透测试,Kill远控软件,初接触
    2019-9-27:渗透测试,metasploit-framework初接触
    2019-9-26:渗透测试,基础学习,js正则以及什么是目录扫描,笔记
    2019-9-26:渗透测试,基础学习,nmap扫描kali虚拟机服务
    2019-9-25:渗透测试,基础学习,Hydra BP爆破,js基本知识,banner信息收集笔记
  • 原文地址:https://www.cnblogs.com/cjqbaba/p/9073908.html
Copyright © 2020-2023  润新知