Halcon13菜鸟 Opencv Mat 转halcon并且显示 vs2013

OpencvHal.h

#include <opencv2/opencv.hpp>  
#include <HalconCpp.h>  
#include <HalconCDefs.h>  
#include <HProto.h>  

using namespace HalconCpp;
//Hobject IplImageToHImage(cv::Mat& pImage);
//cv::Mat HImageToIplImage(Hobject &Hobj);
//HObject MatToHImage(cv::Mat  pImage, HObject   &Hobj);
HImage  IplImageToHImage(cv::Mat& pImage);

OpencvHal.cpp

#include "OpencvHal.h"
HImage  IplImageToHImage(cv::Mat& pImage)
{
    HImage Hobj;
    if (3 == pImage.channels())
    {
        cv::Mat pImageRed, pImageGreen, pImageBlue;
        std::vector<cv::Mat> sbgr(3);
        cv::split(pImage, sbgr);

        int length = pImage.rows * pImage.cols;
        uchar *dataBlue = new uchar[length];
        uchar *dataGreen = new uchar[length];
        uchar *dataRed = new uchar[length];

        int height = pImage.rows;
        int width = pImage.cols;
        for (int row = 0; row <height; row++)
        {
            uchar* ptr = pImage.ptr<uchar>(row);
            for (int col = 0; col < width; col++)
            {
                dataBlue[row * width + col] = ptr[3 * col];
                dataGreen[row * width + col] = ptr[3 * col + 1];
                dataRed[row * width + col] = ptr[3 * col + 2];
            }
        }

        HalconCpp::GenImage3(&Hobj, "byte", width, height, (Hlong)(dataRed), (Hlong)(dataGreen), (Hlong)(dataBlue));
        delete[] dataRed;
        delete[] dataGreen;
        delete[] dataBlue;
    }
    else if (1 == pImage.channels())
    {
        int height = pImage.rows;
        int width = pImage.cols;
        uchar *dataGray = new uchar[width * height];
        memcpy(dataGray, pImage.data, width * height);
        HalconCpp::GenImage1(&Hobj, "byte", width, height, (Hlong)(dataGray));
        delete[] dataGray;
    }

    return Hobj;
}

main.cpp

#include <iostream>
#include <stdio.h>
#include <opencv.hpp>
#include <opencv2/highgui/highgui.hpp>  
#include <opencv2/imgproc/imgproc.hpp>  
#include <opencv2/core/core.hpp>  
#include <highgui.h>

//halcon include

#ifndef __APPLE__
#  include "HalconCpp.h"
#  include "HDevThread.h"
#  if defined(__linux__) && !defined(NO_EXPORT_APP_MAIN)
#    include <X11/Xlib.h>
#  endif
#else
#  ifndef HC_LARGE_IMAGES
#    include <HALCONCpp/HalconCpp.h>
#    include <HALCONCpp/HDevThread.h>
#  else
#    include <HALCONCppxl/HalconCpp.h>
#    include <HALCONCppxl/HDevThread.h>
#  endif
#  include <stdio.h>
#  include <HALCON/HpThread.h>
#  include <CoreFoundation/CFRunLoop.h>
#endif

//user include
#include "OpencvHal.h"

using namespace HalconCpp;

Hlong m_WindowRow = 16;
Hlong m_WindowColumn = 630;
Hlong m_WindowWidth = 630;
Hlong m_WindowHeight = 472;
HalconCpp::HWindow m_Window;


int main(int argc, char* argv[])
{
    cv::VideoCapture cap;// cap(0, CAP_FFMPEG);
    //cap.set(CV_CAP_PROP_FPS, 120);
    //cap.set(CV_CAP_PROP_EXPOSURE, -12.0);
    cap.open(0);
    if (!cap.isOpened())    { return -1; }
    //cap.set(CV_CAP_PROP_FOURCC, CV_FOURCC('M', 'J', 'P', 'G'));
    //cap.set(CV_CAP_PROP_FRAME_WIDTH, 1280);
    //cap.set(CV_CAP_PROP_FRAME_HEIGHT, 720);//如果相机支持的话这几个设置是可行的。


    cv::Mat frame;
    cap >> frame;
    HTuple WindowHandle;

    m_Window.OpenWindow(m_WindowRow, m_WindowColumn,
        m_WindowWidth, m_WindowHeight,
        NULL, "visible", "");
    HImage himg = IplImageToHImage(frame);
    Hlong Width, Height;
    himg.GetImageSize(&Width, &Height);
    m_Window.SetPart(0, 0, Height - 1, Width - 1);
    m_Window.SetLineWidth(3);
    while (true)
    {
        cap >> frame;
        if (frame.empty())
        {
            fprintf(stderr, "Can not load the image file.\n");
            return -1;
        }
        cv::Mat  gray;
        cv::cvtColor(frame, gray, CV_BGR2GRAY);
        cv::imshow("Gray",gray);        
        himg = IplImageToHImage(frame);      
        m_Window.DispObj(himg);  
        cv::waitKey(1);


    }
}

将上述的一个头文件,两个cpp文件加载到工程中,即可以使用opencv和Halcon窗口显示图像。

但是有些从Halcon直接导出的cpp可能没有窗口的初始化,引导到cpp后无法显示图像。是因为HDevWindowStack::IsOpen()值==0。也就是Window没有压栈。
应该添加一些语句。比如我的一个模板匹配匹配工程中的hdev文件如下

read_image (Filename2025, 'E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/filename2025.bmp')
* 
* Matching 01: ************************************************
* Matching 01: BEGIN of generated code for model initialization
* Matching 01: ************************************************
set_system ('border_shape_models', 'false')
* 
* Matching 01: Obtain the model image
read_image (Image, '')
* 
* Matching 01: Build the ROI from basic regions
gen_rectangle1 (ModelRegion, 72.26, 47.172, 223.22, 685.316)
* 
* Matching 01: Reduce the model template
reduce_domain (Image, ModelRegion, TemplateImage)
* 
* Matching 01: Create the shape model
create_shape_model (TemplateImage, 5, rad(0), rad(360), rad(1), ['none','no_pregeneration'], 'use_polarity', [30,30,0], 10, ModelID)
* 
* Matching 01: Get the model contour for transforming it later into the image
get_shape_model_contours (ModelContours, ModelID, 1)
* 
* Matching 01: Get the reference position
area_center (ModelRegion, ModelRegionArea, RefRow, RefColumn)
vector_angle_to_rigid (0, 0, 0, RefRow, RefColumn, 0, HomMat2D)
affine_trans_contour_xld (ModelContours, TransContours, HomMat2D)
* 
* Matching 01: Display the model contours
dev_display (Image)
dev_set_color ('green')
dev_set_draw ('margin')
dev_display (ModelRegion)
dev_display (TransContours)
stop ()
* 
* Matching 01: END of generated code for model initialization
* Matching 01:  * * * * * * * * * * * * * * * * * * * * * * *
* Matching 01: BEGIN of generated code for model application
* 
* Matching 01: Loop over all specified test images
TestImages := ['E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/0.bmp','E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/1.bmp','E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/10.bmp','E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/11.bmp','E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/12.bmp','E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/13.bmp','E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/14.bmp','E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/15.bmp','E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/16.bmp','E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/17.bmp','E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/18.bmp','E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/19.bmp','E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/2.bmp','E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/20.bmp','E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/21.bmp','E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/3.bmp','E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/4.bmp','E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/5.bmp','E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/6.bmp','E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/7.bmp','E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/8.bmp','E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/9.bmp']
for T := 0 to 21 by 1
    * 
    * Matching 01: Obtain the test image
    read_image (Image, TestImages[T])
    * 
    * Matching 01: Find the model
    find_shape_model (Image, ModelID, rad(0), rad(360), 0.5, 0, 0.5, 'least_squares', [5,1], 0.75, Row, Column, Angle, Score)
    * 
    * Matching 01: Transform the model contours into the detected positions
    dev_display (Image)
    for I := 0 to |Score| - 1 by 1
        hom_mat2d_identity (HomMat2D)
        hom_mat2d_rotate (HomMat2D, Angle[I], 0, 0, HomMat2D)
        hom_mat2d_translate (HomMat2D, Row[I], Column[I], HomMat2D)
        affine_trans_contour_xld (ModelContours, TransContours, HomMat2D)
        dev_set_color ('green')
        dev_display (TransContours)
        stop ()
    endfor
endfor
* 
* Matching 01: Clear model when done
stop ()
clear_shape_model (ModelID)
* Matching 01: *******************************************
* Matching 01: END of generated code for model application
* Matching 01: *******************************************
* 

将它引导成cpp后,在cpp文件中要添加几个语句才能正常运行,具体添加的语句后面都有注释 //DisplayPart .只要将 注释//DisplayPart的语句加到程序中相应的位置即可显示。
cpp文件如下

///////////////////////////////////////////////////////////////////////////////
// File generated by HDevelop for HALCON/C++ Version 13.0
///////////////////////////////////////////////////////////////////////////////



#ifndef __APPLE__
#  include "HalconCpp.h"
#  include "HDevThread.h"
#  if defined(__linux__) && !defined(NO_EXPORT_APP_MAIN)
#    include <X11/Xlib.h>
#  endif
#else
#  ifndef HC_LARGE_IMAGES
#    include <HALCONCpp/HalconCpp.h>
#    include <HALCONCpp/HDevThread.h>
#  else
#    include <HALCONCppxl/HalconCpp.h>
#    include <HALCONCppxl/HDevThread.h>
#  endif
#  include <stdio.h>
#  include <HALCON/HpThread.h>
#  include <CoreFoundation/CFRunLoop.h>
#endif



using namespace HalconCpp;
Hlong m_WindowRow = 16; //DisplayPart
Hlong m_WindowColumn = 630;//DisplayPart
Hlong m_WindowWidth = 630;//DisplayPart
Hlong m_WindowHeight = 472;//DisplayPart
HalconCpp::HWindow m_Window;//DisplayPart

#ifndef NO_EXPORT_MAIN
// Main procedure 
void action()
{

    // Local iconic variables
    HObject  ho_Filename2025, ho_Image, ho_ModelRegion;
    HObject  ho_TemplateImage, ho_ModelContours, ho_TransContours;

    // Local control variables
    HTuple  hv_ModelID, hv_ModelRegionArea, hv_RefRow;
    HTuple  hv_RefColumn, hv_HomMat2D, hv_TestImages, hv_T;
    HTuple  hv_Row, hv_Column, hv_Angle, hv_Score, hv_I;

    ReadImage(&ho_Filename2025, "E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/filename2025.bmp");

    m_Window.OpenWindow(m_WindowRow, m_WindowColumn,
        m_WindowWidth, m_WindowHeight,
        NULL, "visible", "");    //DisplayPart
    HTuple Width, Height;//DisplayPart
    GetImageSize(ho_Filename2025, &Width, &Height);//DisplayPart 
    m_Window.SetPart(0, 0, Height.I() - 1, Width.I() - 1);//DisplayPart
    m_Window.SetLineWidth(3);//DisplayPart
    HDevWindowStack::Push((m_Window));//DisplayPart


    //
    //Matching 01: ************************************************
    //Matching 01: BEGIN of generated code for model initialization
    //Matching 01: ************************************************
    SetSystem("border_shape_models", "false");
    //
    //Matching 01: Obtain the model image
    //Matching 01: The image is assumed to be made available in the
    //Matching 01: variable last displayed in the graphics window
    CopyObj(ho_Filename2025, &ho_Image, 1, 1);
    //
    //Matching 01: Build the ROI from basic regions
    GenRectangle1(&ho_ModelRegion, 64.5703, 44.1127, 224.316, 654.908);
    //
    //Matching 01: Reduce the model template
    ReduceDomain(ho_Image, ho_ModelRegion, &ho_TemplateImage);
    //
    //Matching 01: Create the shape model
    CreateShapeModel(ho_TemplateImage, 6, HTuple(0).TupleRad(), HTuple(360).TupleRad(),
        HTuple(0.3898).TupleRad(), (HTuple("none").Append("no_pregeneration")), "use_polarity",
        ((HTuple(42).Append(71)).Append(13)), 4, &hv_ModelID);
    //
    //Matching 01: Get the model contour for transforming it later into the image
    GetShapeModelContours(&ho_ModelContours, hv_ModelID, 1);
    //
    //Matching 01: Get the reference position
    AreaCenter(ho_ModelRegion, &hv_ModelRegionArea, &hv_RefRow, &hv_RefColumn);
    VectorAngleToRigid(0, 0, 0, hv_RefRow, hv_RefColumn, 0, &hv_HomMat2D);
    AffineTransContourXld(ho_ModelContours, &ho_TransContours, hv_HomMat2D);
    //
    //Matching 01: Display the model contours
    if (HDevWindowStack::IsOpen())
        DispObj(ho_Image, HDevWindowStack::GetActive());
    if (HDevWindowStack::IsOpen())
        SetColor(HDevWindowStack::GetActive(), "green");
    if (HDevWindowStack::IsOpen())
        SetDraw(HDevWindowStack::GetActive(), "margin");
    if (HDevWindowStack::IsOpen())
        DispObj(ho_ModelRegion, HDevWindowStack::GetActive());
    if (HDevWindowStack::IsOpen())
        DispObj(ho_TransContours, HDevWindowStack::GetActive());
    // stop(...); only in hdevelop
    //
    //Matching 01: END of generated code for model initialization
    //Matching 01:  * * * * * * * * * * * * * * * * * * * * * * *
    //Matching 01: BEGIN of generated code for model application
    //
    //Matching 01: Loop over all specified test images
    hv_TestImages.Clear();
    hv_TestImages[0] = "E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/0.bmp";
    hv_TestImages[1] = "E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/1.bmp";
    hv_TestImages[2] = "E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/10.bmp";
    hv_TestImages[3] = "E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/11.bmp";
    hv_TestImages[4] = "E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/12.bmp";
    hv_TestImages[5] = "E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/13.bmp";
    hv_TestImages[6] = "E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/14.bmp";
    hv_TestImages[7] = "E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/15.bmp";
    hv_TestImages[8] = "E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/16.bmp";
    hv_TestImages[9] = "E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/17.bmp";
    hv_TestImages[10] = "E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/18.bmp";
    hv_TestImages[11] = "E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/19.bmp";
    hv_TestImages[12] = "E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/2.bmp";
    hv_TestImages[13] = "E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/20.bmp";
    hv_TestImages[14] = "E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/21.bmp";
    hv_TestImages[15] = "E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/3.bmp";
    hv_TestImages[16] = "E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/4.bmp";
    hv_TestImages[17] = "E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/5.bmp";
    hv_TestImages[18] = "E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/6.bmp";
    hv_TestImages[19] = "E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/7.bmp";
    hv_TestImages[20] = "E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/8.bmp";
    hv_TestImages[21] = "E:/VisoStidioprojects/win10Opencv31/MystructlineGige/strctlineGigeFor2D/strctlineGige/9.bmp";
    for (hv_T = 0; hv_T <= 21; hv_T += 1)
    {
        //
        //Matching 01: Obtain the test image
        ReadImage(&ho_Image, HTuple(hv_TestImages[hv_T]));
        GetImageSize(ho_Image, &Width, &Height);//DisplayPart
        m_Window.SetPart(0, 0, Height.I() - 1, Width.I() - 1);//DisplayPart

        //
        //Matching 01: Find the model
        FindShapeModel(ho_Image, hv_ModelID, HTuple(0).TupleRad(), HTuple(360).TupleRad(),
            0.42, 1, 0.5, "least_squares", (HTuple(6).Append(1)), 0.75, &hv_Row, &hv_Column,
            &hv_Angle, &hv_Score);
        //
        //Matching 01: Transform the model contours into the detected positions
        std::cout << "HDevWindowStack::IsOpen()" << HDevWindowStack::IsOpen() << std::endl;
        if (HDevWindowStack::IsOpen())
            DispObj(ho_Image, HDevWindowStack::GetActive());
        {
            HTuple end_val54 = (hv_Score.TupleLength()) - 1;
            HTuple step_val54 = 1;
            for (hv_I = 0; hv_I.Continue(end_val54, step_val54); hv_I += step_val54)
            {
                HomMat2dIdentity(&hv_HomMat2D);
                HomMat2dRotate(hv_HomMat2D, HTuple(hv_Angle[hv_I]), 0, 0, &hv_HomMat2D);
                HomMat2dTranslate(hv_HomMat2D, HTuple(hv_Row[hv_I]), HTuple(hv_Column[hv_I]),
                    &hv_HomMat2D);
                AffineTransContourXld(ho_ModelContours, &ho_TransContours, hv_HomMat2D);
                if (HDevWindowStack::IsOpen())
                    SetColor(HDevWindowStack::GetActive(), "green");
                if (HDevWindowStack::IsOpen())
                    DispObj(ho_TransContours, HDevWindowStack::GetActive());
                // stop(...); only in hdevelop
            }
        }
    }
    //
    //Matching 01: Clear model when done
    // stop(...); only in hdevelop
    ClearShapeModel(hv_ModelID);
    //Matching 01: *******************************************
    //Matching 01: END of generated code for model application
    //Matching 01: *******************************************
    //
}


#ifndef NO_EXPORT_APP_MAIN

#ifdef __APPLE__
// On OS X systems, we must have a CFRunLoop running on the main thread in
// order for the HALCON graphics operators to work correctly, and run the
// action function in a separate thread. A CFRunLoopTimer is used to make sure
// the action function is not called before the CFRunLoop is running.
HTuple      gStartMutex;
H_pthread_t gActionThread;

static void timer_callback(CFRunLoopTimerRef timer, void *info)
{
    UnlockMutex(gStartMutex);
}

static Herror apple_action(void **parameters)
{
    LockMutex(gStartMutex);
    action();
    CFRunLoopStop(CFRunLoopGetMain());
    return H_MSG_OK;
}

static int apple_main(int argc, char *argv[])
{
    Herror                error;
    CFRunLoopTimerRef     Timer;
    CFRunLoopTimerContext TimerContext = { 0, 0, 0, 0, 0 };

    CreateMutex("type", "sleep", &gStartMutex);
    LockMutex(gStartMutex);

    error = HpThreadHandleAlloc(&gActionThread);
    if (H_MSG_OK != error)
    {
        fprintf(stderr, "HpThreadHandleAlloc failed: %d\n", error);
        exit(1);
    }

    error = HpThreadCreate(gActionThread, 0, apple_action);
    if (H_MSG_OK != error)
    {
        fprintf(stderr, "HpThreadCreate failed: %d\n", error);
        exit(1);
    }

    Timer = CFRunLoopTimerCreate(kCFAllocatorDefault,
        CFAbsoluteTimeGetCurrent(), 0, 0, 0,
        timer_callback, &TimerContext);
    if (!Timer)
    {
        fprintf(stderr, "CFRunLoopTimerCreate failed\n");
        exit(1);
    }
    CFRunLoopAddTimer(CFRunLoopGetCurrent(), Timer, kCFRunLoopCommonModes);
    CFRunLoopRun();
    CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), Timer, kCFRunLoopCommonModes);
    CFRelease(Timer);

    error = HpThreadHandleFree(gActionThread);
    if (H_MSG_OK != error)
    {
        fprintf(stderr, "HpThreadHandleFree failed: %d\n", error);
        exit(1);
    }

    ClearMutex(gStartMutex);
    return 0;
}
#endif

int main(int argc, char *argv[])
{
#if defined(_WIN32)
    SetSystem("use_window_thread", "true");
#elif defined(__linux__)
    XInitThreads();
#endif

    // Default settings used in HDevelop (can be omitted) 
    int ret = 0;
    SetSystem("width", 512);
    SetSystem("height", 512);

#ifndef __APPLE__
    action();
#else
    ret = apple_main(argc, argv);
#endif
    return ret;
}

#endif


#endif


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值