千家信息网

C++ OpenCV如何实现银行卡号识别功能

发表于:2026-11-01 作者:千家信息网编辑
千家信息网最后更新 2026年11月01日,这篇文章主要介绍了C++ OpenCV如何实现银行卡号识别功能,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。一、获取模板图像如图所示,
千家信息网最后更新 2026年11月01日C++ OpenCV如何实现银行卡号识别功能

这篇文章主要介绍了C++ OpenCV如何实现银行卡号识别功能,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

一、获取模板图像

如图所示,这是我们的模板图像。我们需要将上面的字符一一切割出来保存,以便进行后续的字符匹配环节。先进行图像灰度、阈值等操作进行轮廓提取,这里就不再细说。这里我想说的是,由于经过轮廓检索,提取出来的字符并不是按(0、1、2…7、8、9)顺序排列,所以,在这里我自定义了一个Card结构体,用于图像排序。具体请看源码。

1.1 功能效果

如图为顺序切割出来的模板字符。

1.2 功能源码

bool Get_Template(Mat temp, vector&Card_Temp){    //图像预处理    Mat gray;    cvtColor(temp, gray, COLOR_BGR2GRAY);    Mat thresh;    threshold(gray, thresh, 0, 255, THRESH_BINARY_INV|THRESH_OTSU);    //轮廓检测    vector > contours;    findContours(thresh, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);    for (int i = 0; i < contours.size(); i++)    {        Rect rect = boundingRect(contours[i]);        double ratio = double(rect.width) / double(rect.height);        //筛选出字符轮廓        if (ratio > 0.5 && ratio < 1)        {            /*rectangle(temp, rect, Scalar(0, 255, 0));*/            Mat roi = temp(rect);  //将字符扣出,放入Card_Temp容器备用            Card_Temp.push_back({ roi ,rect });        }    }    if (Card_Temp.empty())return false;    //进行字符排序,使其按(0、1、2...7、8、9)顺序排序    for (int i = 0; i < Card_Temp.size()-1; i++)    {        for (int j = 0; j < Card_Temp.size() - 1 - i; j++)        {            if (Card_Temp[j].rect.x > Card_Temp[j + 1].rect.x)            {                Card temp = Card_Temp[j];                Card_Temp[j] = Card_Temp[j + 1];                Card_Temp[j + 1] = temp;            }        }    }    return true;}

二、银行卡号定位

如图所示,这是本案例需要识别的银行卡。从图中可以看出,我们需要将银行卡号切割出来首先得将卡号分为4个小块切割,之后再需要将每一小块上的字符切割。接下来一步步看是如何操作的。

2.1 将银行卡号切割成四块

首先第一步得先进行图像预处理,通过灰度、二值化、形态学等操作提取出卡号轮廓。这里的图像预处理需要根据图像特征自行确定,并不是所有的步骤都是必须的,我们最终的目的是为了定位银行卡号所在轮廓位置。这里我使用的是二值化、以及形态学闭操作。

 //形态学操作、以便找到银行卡号区域轮廓    Mat gray;    cvtColor(src, gray, COLOR_BGR2GRAY);    Mat gaussian;    GaussianBlur(gray, gaussian, Size(3, 3), 0);    Mat thresh;    threshold(gaussian, thresh, 0, 255, THRESH_BINARY | THRESH_OTSU);    Mat close;    Mat kernel2 = getStructuringElement(MORPH_RECT, Size(15, 5));    morphologyEx(thresh, close, MORPH_CLOSE, kernel2);

经过灰度、阈值、形态学操作后的图像如下图所示。我们已经将银行卡号分为四个小矩形块,接下来只需通过轮廓查找、筛选就可以扣出这四个ROI区域了。

  vector>contours;    findContours(close, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);    for (int i = 0; i < contours.size(); i++)    {        //通过面积、长宽比筛选出银行卡号区域        double area = contourArea(contours[i]);        if (area > 800 && area < 1400)        {            Rect rect = boundingRect(contours[i]);            float ratio = double(rect.width) / double(rect.height);            if (ratio > 2.8 && ratio < 3.1)            {                Mat ROI = src(rect);                Block_ROI.push_back({ ROI ,rect });            }        }    }

同理,我们需要将切割下来的小块按照它原来的顺序存储。

    for (int i = 0; i < Block_ROI.size()-1; i++)    {        for (int j = 0; j < Block_ROI.size() - 1 - i; j++)        {            if (Block_ROI[j].rect.x > Block_ROI[j + 1].rect.x)            {                Card temp = Block_ROI[j];                Block_ROI[j] = Block_ROI[j + 1];                Block_ROI[j + 1] = temp;            }        }    }

2.1.1 功能效果

2.1.2 功能源码

bool Cut_Block(Mat src, vector&Block_ROI){    //形态学操作、以便找到银行卡号区域轮廓    Mat gray;    cvtColor(src, gray, COLOR_BGR2GRAY);    Mat gaussian;    GaussianBlur(gray, gaussian, Size(3, 3), 0);    Mat thresh;    threshold(gaussian, thresh, 0, 255, THRESH_BINARY | THRESH_OTSU);    Mat close;    Mat kernel2 = getStructuringElement(MORPH_RECT, Size(15, 5));    morphologyEx(thresh, close, MORPH_CLOSE, kernel2);    vector>contours;    findContours(close, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);    for (int i = 0; i < contours.size(); i++)    {        //通过面积、长宽比筛选出银行卡号区域        double area = contourArea(contours[i]);        if (area > 800 && area < 1400)        {            Rect rect = boundingRect(contours[i]);            float ratio = double(rect.width) / double(rect.height);            if (ratio > 2.8 && ratio < 3.1)            {                //rectangle(src, rect, Scalar(0, 255, 0), 2);                Mat ROI = src(rect);                Block_ROI.push_back({ ROI ,rect });            }        }    }        if (Block_ROI.size()!=4)return false;    for (int i = 0; i < Block_ROI.size()-1; i++)    {        for (int j = 0; j < Block_ROI.size() - 1 - i; j++)        {            if (Block_ROI[j].rect.x > Block_ROI[j + 1].rect.x)            {                Card temp = Block_ROI[j];                Block_ROI[j] = Block_ROI[j + 1];                Block_ROI[j + 1] = temp;            }        }    }    //for (int i = 0; i < Block_ROI.size(); i++)    //{    //    imshow(to_string(i), Block_ROI[i].mat);    //    waitKey(0);    //}    return true;}

2.2 字符切割

由步骤2.1,我们已经将银行卡号定位,且顺序切割成四个小块。接下来,我们只需要将他们依次的将字符切割下来就可以了。其实切割字符跟上面的切割小方块是差不多的,这里就不再多说了。在这里我着重要说明的是,切割出来的字符相对于银行卡所在位置。

由步骤2.1,我们顺序切割出来四个小方块。以其中一个小方块为例,当时我们存储了rect变量,它表示该小方块相对于图像起点(X,Y),宽W,高H。而步骤2.2我们需要做的就是将这个小方块的字符切割出来,那么每一个字符相对于小方块所在位置为起点(x,y),宽w,高h。所以,这些字符相当于银行卡所在位置就是起点(X+x,Y+y),宽 (w),高(h)。具体请细看源码。也比较简单容易理解。

 //循环上面切割出来的四个小块,将上面的字符一一切割出来。    for (int i = 0; i < Block_ROI.size(); i++)    {        Mat roi_gray;        cvtColor(Block_ROI[i].mat, roi_gray, COLOR_BGR2GRAY);        Mat roi_thresh;        threshold(roi_gray, roi_thresh, 0, 255, THRESH_BINARY|THRESH_OTSU);        vector > contours;        findContours(roi_thresh, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);        for (int j = 0; j < contours.size(); j++)        {            Rect rect = boundingRect(contours[j]);            //字符相对于银行卡所在的位置            Rect roi_rect(rect.x + Block_ROI[i].rect.x, rect.y + Block_ROI[i].rect.y, rect.width, rect.height);                Mat r_roi = Block_ROI[i].mat(rect);            Slice_ROI.push_back({ r_roi ,roi_rect });                }    }

同样,在这里我们也需要将切割出来的字符顺序排序。即银行卡上的号码是怎样排序的,我们就需要怎样排序保存

    for (int i = 0; i < Slice_ROI.size() - 1; i++)    {        for (int j = 0; j < Slice_ROI.size() - 1 - i; j++)        {            if (Slice_ROI[j].rect.x > Slice_ROI[j + 1].rect.x)            {                Card temp = Slice_ROI[j];                Slice_ROI[j] = Slice_ROI[j + 1];                Slice_ROI[j + 1] = temp;            }        }    }

2.2.1 功能效果

如图为顺序切割出来的字符

2.2.2 功能源码

bool Cut_Slice(vector&Block_ROI,vector&Slice_ROI){    //循环上面切割出来的四个小块,将上面的字符一一切割出来。    for (int i = 0; i < Block_ROI.size(); i++)    {        Mat roi_gray;        cvtColor(Block_ROI[i].mat, roi_gray, COLOR_BGR2GRAY);        Mat roi_thresh;        threshold(roi_gray, roi_thresh, 0, 255, THRESH_BINARY|THRESH_OTSU);        vector > contours;        findContours(roi_thresh, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);        for (int j = 0; j < contours.size(); j++)        {            Rect rect = boundingRect(contours[j]);            //字符相对于银行卡所在的位置            Rect roi_rect(rect.x + Block_ROI[i].rect.x, rect.y + Block_ROI[i].rect.y, rect.width, rect.height);                Mat r_roi = Block_ROI[i].mat(rect);            Slice_ROI.push_back({ r_roi ,roi_rect });                }    }    if (Slice_ROI.size() != 16) return false;    for (int i = 0; i < Slice_ROI.size() - 1; i++)    {        for (int j = 0; j < Slice_ROI.size() - 1 - i; j++)        {            if (Slice_ROI[j].rect.x > Slice_ROI[j + 1].rect.x)            {                Card temp = Slice_ROI[j];                Slice_ROI[j] = Slice_ROI[j + 1];                Slice_ROI[j + 1] = temp;            }        }    }    //for (int i = 0; i < Slice_ROI.size(); i++)    //{    //    imshow(to_string(i), Slice_ROI[i].mat);    //    waitKey(0);    //}    return true;}

三、字符识别

3.1.读取文件

如图所示,为模板图像对应的label。我们需要读取文件,进行匹配。

bool ReadData(string filename, vector&label){    fstream fin;    fin.open(filename, ios::in);    if (!fin.is_open())    {        cout << "can not open the file!" << endl;        return false;    }    int data[10] = { 0 };    for (int i = 0; i < 10; i++)    {        fin >> data[i];    }    fin.close();    for (int i = 0; i < 10; i++)    {        label.push_back(data[i]);    }    return true;}

3.2.字符匹配

在这里,我的思路是:使用一个for循环,将我们切割出来的字符与现有的模板一一进行匹配。使用的算法是图像模板匹配matchTemplate。具体用法请大家自行查找相关资料。具体请看源码

3.3.功能源码

bool Template_Matching(vector&Card_Temp,    vector&Block_ROI, vector&Slice_ROI,    vector&result_index){    for (int i = 0; i < Slice_ROI.size(); i++)    {        //将字符resize成合适大小,利于识别        resize(Slice_ROI[i].mat, Slice_ROI[i].mat, Size(60, 80), 1, 1, INTER_LINEAR);        Mat gray;        cvtColor(Slice_ROI[i].mat, gray, COLOR_BGR2GRAY);        int maxIndex = 0;        double Max = 0.0;        for (int j = 0; j < Card_Temp.size(); j++)        {                    resize(Card_Temp[j].mat, Card_Temp[j].mat, Size(60, 80), 1, 1, INTER_LINEAR);            Mat temp_gray;            cvtColor(Card_Temp[j].mat, temp_gray, COLOR_BGR2GRAY);            //进行模板匹配,识别数字            Mat result;            matchTemplate(gray, temp_gray, result, TM_SQDIFF_NORMED);            double minVal, maxVal;            Point minLoc, maxLoc;            minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc);                        //得分最大的视为匹配结果            if (maxVal > Max)            {                Max = maxVal;                maxIndex = j; //匹配结果            }        }        result_index.push_back(maxIndex);//将匹配结果进行保存    }    if (result_index.size() != 16)return false;    return true;}

四、效果显示

4.1 功能源码

bool Show_Result(Mat src,     vector&Block_ROI,    vector&Slice_ROI,     vector&result_index){    //读取label标签    vectorlabel;    if (!ReadData("label.txt", label))return false;    //将匹配结果进行显示    for (int i = 0; i < Block_ROI.size(); i++)    {        rectangle(src, Rect(Block_ROI[i].rect.tl(), Block_ROI[i].rect.br()), Scalar(0, 255, 0), 2);    }    for (int i = 0; i < Slice_ROI.size(); i++)    {        cout << label[result_index[i]] << " ";        putText(src, to_string(label[result_index[i]]), Point(Slice_ROI[i].rect.tl()), FONT_HERSHEY_SIMPLEX, 1, Scalar(0, 0, 255), 2);    }    imshow("Demo", src);    waitKey(0);    destroyAllWindows();    return true;}

4.2 效果显示

如图所示,为本案例最终的效果展示。

五、源码

5.1 hpp文件

#pragma once#include#includestruct Card{        cv::Mat mat;        cv::Rect rect;};//获取模板图像bool Get_Template(cv::Mat temp, std::vector&Card_Temp);//将银行卡卡号部分切成四块bool Cut_Block(cv::Mat src, std::vector&Block_ROI);//将每一块数字区域切分出单独数字bool Cut_Slice(std::vector&Block_ROI, std::vector&Slice_ROI);//将数字与模板进行模板匹配bool Template_Matching(std::vector&Card_Temp,         std::vector&Block_ROI,        std::vector&Slice_ROI,        std::vector&result_index);//显示最终结果bool Show_Result(cv::Mat src,        std::vector&Block_ROI,         std::vector&Slice_ROI,        std::vector&result_index);

5.2 cpp文件

#include#include"CardDectection.h"#includeusing namespace std;using namespace cv;bool Get_Template(Mat temp, vector&Card_Temp){        //图像预处理        Mat gray;        cvtColor(temp, gray, COLOR_BGR2GRAY);        Mat thresh;        threshold(gray, thresh, 0, 255, THRESH_BINARY_INV|THRESH_OTSU);        //轮廓检测        vector > contours;        findContours(thresh, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);        for (int i = 0; i < contours.size(); i++)        {                Rect rect = boundingRect(contours[i]);                double ratio = double(rect.width) / double(rect.height);                //筛选出字符轮廓                if (ratio > 0.5 && ratio < 1)                {                        /*rectangle(temp, rect, Scalar(0, 255, 0));*/                        Mat roi = temp(rect);  //将字符扣出,放入Card_Temp容器备用                        Card_Temp.push_back({ roi ,rect });                }        }        if (Card_Temp.empty())return false;        //进行字符排序,使其按(0、1、2...7、8、9)顺序排序        for (int i = 0; i < Card_Temp.size()-1; i++)        {                for (int j = 0; j < Card_Temp.size() - 1 - i; j++)                {                        if (Card_Temp[j].rect.x > Card_Temp[j + 1].rect.x)                        {                                Card temp = Card_Temp[j];                                Card_Temp[j] = Card_Temp[j + 1];                                Card_Temp[j + 1] = temp;                        }                }        }        //for (int i = 0; i < Card_Temp.size(); i++)        //{        //      imshow(to_string(i), Card_Temp[i].mat);        //      waitKey(0);        //}        return true;}bool Cut_Block(Mat src, vector&Block_ROI){        //形态学操作、以便找到银行卡号区域轮廓        Mat gray;        cvtColor(src, gray, COLOR_BGR2GRAY);        Mat gaussian;        GaussianBlur(gray, gaussian, Size(3, 3), 0);        Mat thresh;        threshold(gaussian, thresh, 0, 255, THRESH_BINARY | THRESH_OTSU);        Mat close;        Mat kernel2 = getStructuringElement(MORPH_RECT, Size(15, 5));        morphologyEx(thresh, close, MORPH_CLOSE, kernel2);        vector>contours;        findContours(close, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);        for (int i = 0; i < contours.size(); i++)        {                //通过面积、长宽比筛选出银行卡号区域                double area = contourArea(contours[i]);                if (area > 800 && area < 1400)                {                        Rect rect = boundingRect(contours[i]);                        float ratio = double(rect.width) / double(rect.height);                        if (ratio > 2.8 && ratio < 3.1)                        {                                //rectangle(src, rect, Scalar(0, 255, 0), 2);                                Mat ROI = src(rect);                                Block_ROI.push_back({ ROI ,rect });                        }                }        }                if (Block_ROI.size()!=4)return false;        for (int i = 0; i < Block_ROI.size()-1; i++)        {                for (int j = 0; j < Block_ROI.size() - 1 - i; j++)                {                        if (Block_ROI[j].rect.x > Block_ROI[j + 1].rect.x)                        {                                Card temp = Block_ROI[j];                                Block_ROI[j] = Block_ROI[j + 1];                                Block_ROI[j + 1] = temp;                        }                }        }        //for (int i = 0; i < Block_ROI.size(); i++)        //{        //      imshow(to_string(i), Block_ROI[i].mat);        //      waitKey(0);        //}        return true;}bool Cut_Slice(vector&Block_ROI,vector&Slice_ROI){        //循环上面切割出来的四个小块,将上面的字符一一切割出来。        for (int i = 0; i < Block_ROI.size(); i++)        {                Mat roi_gray;                cvtColor(Block_ROI[i].mat, roi_gray, COLOR_BGR2GRAY);                Mat roi_thresh;                threshold(roi_gray, roi_thresh, 0, 255, THRESH_BINARY|THRESH_OTSU);                vector > contours;                findContours(roi_thresh, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);                for (int j = 0; j < contours.size(); j++)                {                        Rect rect = boundingRect(contours[j]);                        //字符相对于银行卡所在的位置                        Rect roi_rect(rect.x + Block_ROI[i].rect.x, rect.y + Block_ROI[i].rect.y, rect.width, rect.height);                             Mat r_roi = Block_ROI[i].mat(rect);                        Slice_ROI.push_back({ r_roi ,roi_rect });                                }        }        if (Slice_ROI.size() != 16) return false;        for (int i = 0; i < Slice_ROI.size() - 1; i++)        {                for (int j = 0; j < Slice_ROI.size() - 1 - i; j++)                {                        if (Slice_ROI[j].rect.x > Slice_ROI[j + 1].rect.x)                        {                                Card temp = Slice_ROI[j];                                Slice_ROI[j] = Slice_ROI[j + 1];                                Slice_ROI[j + 1] = temp;                        }                }        }        //for (int i = 0; i < Slice_ROI.size(); i++)        //{        //      imshow(to_string(i), Slice_ROI[i].mat);        //      waitKey(0);        //}        return true;}bool ReadData(string filename, vector&label){        fstream fin;        fin.open(filename, ios::in);        if (!fin.is_open())        {                cout << "can not open the file!" << endl;                return false;        }        int data[10] = { 0 };        for (int i = 0; i < 10; i++)        {                fin >> data[i];        }        fin.close();        for (int i = 0; i < 10; i++)        {                label.push_back(data[i]);        }        return true;}bool Template_Matching(vector&Card_Temp,        vector&Block_ROI, vector&Slice_ROI,        vector&result_index){        for (int i = 0; i < Slice_ROI.size(); i++)        {                //将字符resize成合适大小,利于识别                resize(Slice_ROI[i].mat, Slice_ROI[i].mat, Size(60, 80), 1, 1, INTER_LINEAR);                Mat gray;                cvtColor(Slice_ROI[i].mat, gray, COLOR_BGR2GRAY);                int maxIndex = 0;                double Max = 0.0;                for (int j = 0; j < Card_Temp.size(); j++)                {                                       resize(Card_Temp[j].mat, Card_Temp[j].mat, Size(60, 80), 1, 1, INTER_LINEAR);                        Mat temp_gray;                        cvtColor(Card_Temp[j].mat, temp_gray, COLOR_BGR2GRAY);                        //进行模板匹配,识别数字                        Mat result;                        matchTemplate(gray, temp_gray, result, TM_SQDIFF_NORMED);                        double minVal, maxVal;                        Point minLoc, maxLoc;                        minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc);                                                //得分最大的视为匹配结果                        if (maxVal > Max)                        {                                Max = maxVal;                                maxIndex = j; //匹配结果                        }                }                result_index.push_back(maxIndex);//将匹配结果进行保存        }        if (result_index.size() != 16)return false;        return true;}bool Show_Result(Mat src,         vector&Block_ROI,        vector&Slice_ROI,         vector&result_index){        //读取label标签        vectorlabel;        if (!ReadData("label.txt", label))return false;        //将匹配结果进行显示        for (int i = 0; i < Block_ROI.size(); i++)        {                rectangle(src, Rect(Block_ROI[i].rect.tl(), Block_ROI[i].rect.br()), Scalar(0, 255, 0), 2);        }        for (int i = 0; i < Slice_ROI.size(); i++)        {                cout << label[result_index[i]] << " ";                putText(src, to_string(label[result_index[i]]), Point(Slice_ROI[i].rect.tl()), FONT_HERSHEY_SIMPLEX, 1, Scalar(0, 0, 255), 2);        }        imshow("Demo", src);        waitKey(0);        destroyAllWindows();        return true;}

5.3 main文件

#include#include"CardDectection.h"using namespace std;using namespace cv;int main(){        Mat src = imread("card.png");   //源图像 银行卡        Mat temp = imread("number.png"); //模板图像        if (src.empty() || temp.empty())        {                cout << "no image data !" << endl;                system("pause");                return -1;        }        vectorCard_Temp;        if (!Get_Template(temp, Card_Temp))        {                cout << "模板切割失败!" << endl;                system("pause");                return -1;        }        vectorBlock_ROI;        if (Cut_Block(src, Block_ROI))        {                vectorSlice_ROI;                if (Cut_Slice(Block_ROI, Slice_ROI))                {                        vectorresult_index;                        if (Template_Matching(Card_Temp, Block_ROI, Slice_ROI, result_index))                        {                                Show_Result(src, Block_ROI, Slice_ROI, result_index);                        }                        else                        {                                cout << "识别失败!" << endl;                                system("pause");                                return -1;                        }                }                else                {                        cout << "切片失败!" << endl;                        system("pause");                        return -1;                }        }        else        {                cout << "切块失败!" << endl;                system("pause");                return -1;        }        system("pause");        return 0;}

感谢你能够认真阅读完这篇文章,希望小编分享的"C++ OpenCV如何实现银行卡号识别功能"这篇文章对大家有帮助,同时也希望大家多多支持,关注行业资讯频道,更多相关知识等着你来学习!

字符 银行 图像 卡号 模板 功能 轮廓 源码 银行卡 顺序 排序 位置 所在 结果 形态 形态学 效果 方块 如图 区域 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 咖啡 互联网科技作文 九亚互联网科技 互联网女皇 腾讯科技 兼蜜互联网科技 居家互联网科技有限公司 银川新华互联网科技学校地址 湖南诚度互联网科技有限公司 来此购互联网科技有限公司 科技互联网大厂 中国航天科技大学国际工业互联网 广州市恰铎互联网科技有限公司 互联网科技和信息 浙南科技城互联网大厦建设工程 江苏互联网科技小贷 广东鹅鹅鹅互联网科技有限公司 广州三三互联网科技有限公司 唐山双旺合互联网科技产业园 盐城市攀科互联网科技有限公司 恒生互联网科技趋势 互联网科技公司的优势 科技类互联网 喔噻互联网科技 湖南洣水互联网科技有限公司扣款 中国航天科技大学国际工业互联网 互联网科技公司营业执照怎么办理 合肥互联网科技公司公章图片 互联网的科技体现在哪里 山东蛋芒互联网科技有限公司 河南商务圈互联网科技有限公司
0