gige工业相机突破(二,c++实现)

调试通过别人的代码,gige 500万工业相机海康。

如果你下载了open gige vision 代码,你可以参考我下面的代码(可以打开相机并取像显示):

  /* if(argc != 3)
      throw std::runtime_error(str(boost::format("Usage: %1% <ip> <port>") % argv[0]));*/

    GigEVision vis;

     //char ip[16];   
  //  wcstombs(ip, _T(argv[1]), sizeof(ip));
     //char port[16];   
  //  wcstombs(port, _T(argv[2]), sizeof(port));
      vis.Gvcp().Connect("192.168.20.54", "3956");//192.168.20.48本地客户端,链接相机192.168.20.54服务器端
    //  vis.Gvcp().Connect("169.254.0.2", "12221");//192.168.20.48本地,相机192.168.20.54服务器端
  //  vis.Gvcp().Connect(argv[1], argv[2]);
      std::string hello=vis.Gvcp().FindCam().to_string();//返回的是远端设备gige相机地址202403081043//
  //  std::cout << "Cam Addr: " << vis.Gvcp().FindCam().to_string() << std::endl;

     

    vis.GenICam().ReadXmlFile();
    vis.GenICam().PrintNodes();

    // format bool values as strings,通过字符串格式布尔值,这些字符串是通过读xml得到的,这里的字符串相当于命令,很像当年vc6.0打开关闭光驱的情形。202403111002
    std::cout.setf (std::ios::boolalpha);

以上代码最关键是,标红的,其他不重要。再看接下来:

//读相机width
    boost::array<uint8_t, 16> buff = {0x42, 0x01, 0x00, 0x80, 0x00, 0x04,
        0x00, 0x91, 0x00, 0x03, 0x03, 0x60, 0x00, 0x00, 0x00, 0x00};
     vis.Gvcp().m_sock.send_to(boost::asio::buffer(buff), *vis.Gvcp().m_it);
      boost::array<uint8_t, 12> recv_buf;
  boost::asio::ip::udp::endpoint sender_endpoint;
  if(vis.Gvcp().m_sock.receive_from(boost::asio::buffer(recv_buf), sender_endpoint) == 12)
  {
       recv_buf[0] == 0x00;
        recv_buf[1] == 0x00;
         recv_buf[2] == 0x00;
          recv_buf[3] == 0x81;
           recv_buf[4] == 0x00;
            recv_buf[5] == 0x04;
       recv_buf[6] == 0x00;
       recv_buf[7] == 0x91;
        recv_buf[8] == 0x00;
         recv_buf[9] == 0x00;
          recv_buf[10] == 0x0a;
           recv_buf[11] == 0x20;
           //r如果返回如此,width=2592=registervalue=0x0a20
  }
  //读相机height
    boost::array<uint8_t, 16>
        buff1 = {0x42, 0x01, 0x00, 0x80, 0x00, 0x04,
        0x00, 0x92, 0x00, 0x03, 0x03, 0xa0, 0x00, 0x00, 0x00, 0x00};
     vis.Gvcp().m_sock.send_to(boost::asio::buffer(buff1), *vis.Gvcp().m_it);
      boost::array<uint8_t, 12> recv_buf2;
 // boost::asio::ip::udp::endpoint sender_endpoint;
  if(vis.Gvcp().m_sock.receive_from(boost::asio::buffer(recv_buf2), sender_endpoint) == 12)
  {
     
          recv_buf2[10] == 0x07;
           recv_buf2[11] == 0x98;
           //如果返回如此,width=1944=registervalue=0x0798
  }
   //读相机canshu offsetx?
    boost::array<uint8_t, 16>
        buff3 = {0x42, 0x01, 0x00, 0x80, 0x00, 0x04,
        0x00, 0x93, 0x00, 0x03, 0x03, 0x0e0, 0x00, 0x00, 0x00, 0x00};
     vis.Gvcp().m_sock.send_to(boost::asio::buffer(buff3), *vis.Gvcp().m_it);
      boost::array<uint8_t, 12> recv_buf3;
//  boost::asio::ip::udp::endpoint sender_endpoint;
    if(vis.Gvcp().m_sock.receive_from(boost::asio::buffer(recv_buf3), sender_endpoint) == 12)
  {
         recv_buf3[11] == 0;
           recv_buf3[10] == 0;
           //如果返回如此,offsetx=0=registervalue=0x00
    }
      //读相机canshu offsety?
    boost::array<uint8_t, 16>
        buff4 = {0x42, 0x01, 0x00, 0x80, 0x00, 0x04,
        0x00, 0x94, 0x00, 0x03, 0x04, 0x20, 0x00, 0x00, 0x00, 0x00};
     vis.Gvcp().m_sock.send_to(boost::asio::buffer(buff4), *vis.Gvcp().m_it);
      boost::array<uint8_t, 12> recv_buf4;
//  boost::asio::ip::udp::endpoint sender_endpoint;
    if(vis.Gvcp().m_sock.receive_from(boost::asio::buffer(recv_buf4), sender_endpoint) == 12)
  {
         recv_buf4[11] == 0;
           recv_buf4[10] == 0;
           //如果返回如此,offsety=0=registervalue=0x00
    }

      //读相机canshu pixformat?
    boost::array<uint8_t, 16>
        buff5 = {0x42, 0x01, 0x00, 0x80, 0x00, 0x04,
        0x00, 0x95, 0x00, 0x03, 0x06, 0x10, 0x00, 0x00, 0x00, 0x00};
     vis.Gvcp().m_sock.send_to(boost::asio::buffer(buff5), *vis.Gvcp().m_it);
      boost::array<uint8_t, 12> recv_buf5;
 // boost::asio::ip::udp::endpoint sender_endpoint;
    if(vis.Gvcp().m_sock.receive_from(boost::asio::buffer(recv_buf5), sender_endpoint) == 12)
  {
        recv_buf5[11] == 0x01;
           recv_buf5[10] == 0x00;
         recv_buf5[9] == 0x08;
           recv_buf5[8] == 0x01;
           //如果返回如此,pixformat=17301505=registervalue="mono8"=01080001
    }
    //初始化接受数组202403141044
    // rawBytes = new byte[Width * Height * bytesPerPixel];
    //xmlisloaded=true;IsStreaming=false;准备打开流通道,先要控制

     //开始控制,向寄存器写入
    boost::array<uint8_t, 16>
        buff6= {0x42, 0x01, 0x00, 0x80, 0x00, 0x04,
        0x01, 0x28, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00};
     vis.Gvcp().m_sock.send_to(boost::asio::buffer(buff6), *vis.Gvcp().m_it);
      boost::array<uint8_t, 12> recv_buf6;
 // boost::asio::ip::udp::endpoint sender_endpoint;
    if(vis.Gvcp().m_sock.receive_from(boost::asio::buffer(recv_buf6), sender_endpoint) == 12)
  {
        recv_buf6[11] == 0x00;
           recv_buf6[10] == 0x00;
         recv_buf6[9] == 0x00;
           recv_buf6[8] == 0x00;
           //如果返回如此,its free can be control
    }

         //开始控制,向寄存器写入
    boost::array<uint8_t, 16>
        buff7= {0x42, 0x01, 0x00, 0x82, 0x00, 0x08,
        0x01, 0x29, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x02};
     vis.Gvcp().m_sock.send_to(boost::asio::buffer(buff7), *vis.Gvcp().m_it);
      boost::array<uint8_t, 12> recv_buf7;
 // boost::asio::ip::udp::endpoint sender_endpoint;
    if(vis.Gvcp().m_sock.receive_from(boost::asio::buffer(recv_buf7), sender_endpoint) == 12)
  {
        recv_buf7[11] == 0x01;
           recv_buf7[10] == 0x00;
         recv_buf7[9] == 0x00;
           recv_buf7[8] == 0x00;
           //如果返回如此, recv_buf7[11] == 0x01;开始设置心跳,循环5次,如果拒绝,进入心跳线程
    }

for(int i=0;i<5;i++)//怎样判断gvcpReply.status==success?如果在5次内设置成功了,就要跳出来
    {
        uint8_t hello=0x2d;
        boost::array<uint8_t, 16>
        buff8= {0x42, 0x01, 0x00, 0x82, 0x00, 0x08,
        0x01, hello, 0x00, 0x00, 0x09, 0x38, 0x00, 0x00, 0x27, 0x10};
     vis.Gvcp().m_sock.send_to(boost::asio::buffer(buff8), *vis.Gvcp().m_it);

      boost::array<uint8_t, 12> recv_buf8;
      vis.Gvcp().m_sock.receive_from(boost::asio::buffer(recv_buf8), sender_endpoint);

      hello++;

      if(recv_buf8[11]==1)
      {
          //成功了?
          i=5;
          break;
      }
    }


    vis.Gvcp().StartHeartbeat();
      Sleep(10);

讲解:这些代码中和gige相机的互动最为关键,像极了一问一答。特别是心跳的正常运转(以前工程中与电控通信,老是觉得plc的心跳不重要,有怠慢,在此已经意识到,请包涵我的无知),继续代码:

    int iFd;//套接字
        //以下用winsock绑定套接字udp多播是ok的,暂时不用,注释
    struct sockaddr_in Addr;

if ((iFd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
        {
            printf("socket fail\n");
            //return -1;
        }

memset(&Addr, 0, sizeof(struct sockaddr_in));
    Addr.sin_family = AF_INET;

Addr.sin_addr.s_addr = inet_addr("192.168.20.48");//本地地址192.168.20.48
        Addr.sin_port = htons(63378);//多播的端口,端口用63378

 if (bind(iFd, (struct sockaddr *)&Addr, sizeof(Addr)) == -1)//绑定
    {
        printf("bind failed!\n");
    }
    else
    {
        printf("bind ok\n");
    }

 //开始控制,向寄存器写入GevSCPHostPort
    boost::array<uint8_t, 16>
        buff9= {0x42, 0x01, 0x00, 0x82, 0x00, 0x08,
        0x01, 0x2e, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0f7, 0x92};//写入端口port=63378
     vis.Gvcp().m_sock.send_to(boost::asio::buffer(buff9), *vis.Gvcp().m_it);
      boost::array<uint8_t, 12> recv_buf9;
 // boost::asio::ip::udp::endpoint sender_endpoint;
    if(vis.Gvcp().m_sock.receive_from(boost::asio::buffer(recv_buf9), sender_endpoint) == 12)
  {
        recv_buf9[11] == 0x01;
         
           //如果返回如此, recv_buf9[11] == 0x01;GevSCPHostPort写入ok
    }

     //开始控制,向寄存器写入GevSCDA
    boost::array<uint8_t, 16>
        buff10= {0x42, 0x01, 0x00, 0x82, 0x00, 0x08,
        //0x01, 0x2f, 0x00, 0x00, 0x0d, 24, 239, 192, 11, 12};//使用多播地址
            0x01, 0x2f, 0x00, 0x00, 0x0d, 24, 192, 168, 20, 48};//多播地址?
     vis.Gvcp().m_sock.send_to(boost::asio::buffer(buff10), *vis.Gvcp().m_it);
      boost::array<uint8_t, 12> recv_buf10;
 // boost::asio::ip::udp::endpoint sender_endpoint;
    if(vis.Gvcp().m_sock.receive_from(boost::asio::buffer(recv_buf10), sender_endpoint) == 12)
  {
        recv_buf10[11] == 0x01;
         
           //如果返回如此, recv_buf10[11] == 0x01;GevSCDA写入ok
    }

    /*  <Integer Name="ExposureTime_RegAddr">
    <Value>
      0x00030b04
    </Value>*/


boost::array<uint8_t, 16>
        buffex= {0x42, 0x01, 0x00, 0x82, 0x00, 0x08,
        0x03, 0x2f, 0x00, 0x03, 0x0b, 0x04,0,0,0x61,0x0a8};
     vis.Gvcp().m_sock.send_to(boost::asio::buffer(buffex), *vis.Gvcp().m_it);

      boost::array<uint8_t, 12> recv_bufex;

       if(vis.Gvcp().m_sock.receive_from(boost::asio::buffer(recv_bufex), sender_endpoint) == 12)
  {
        recv_bufex[11] == 0x01;
        //  if( recv_bufex[11] ==136&& recv_bufex[10] == 19)    //如果曝光值是5000,设置为25000=0x61,0x0a8      
        //  {
        //boost::array<uint8_t, 16>      buffex25000= {0x42, 0x01, 0x00, 0x80, 0x00, 0x04,
        //0x01, 0x30, 0x00, 0x03, 0x0b, 0x04,64,0,0x61,0x0a8};
     //vis.Gvcp().m_sock.send_to(boost::asio::buffer(buffex25000), *vis.Gvcp().m_it);
        //  }
       }


    bool mtu1500=false;
    //开始控制,向寄存器写入 var gevSCPSPacketSize
= (await Gvcp.GetRegister(nameof(GvcpRegister.GevSCPSPacketSize))).pValue;//地址0x0d04
    boost::array<uint8_t, 16>
        buff11= {0x42, 0x01, 0x00, 0x80, 0x00, 0x04,
        0x01, 0x30, 0x00, 0x00, 0x0d, 0x04};
     vis.Gvcp().m_sock.send_to(boost::asio::buffer(buff11), *vis.Gvcp().m_it);
      boost::array<uint8_t, 12> recv_buf11;
 // boost::asio::ip::udp::endpoint sender_endpoint;
    if(vis.Gvcp().m_sock.receive_from(boost::asio::buffer(recv_buf11), sender_endpoint) == 12)
  {
        recv_buf11[11] == 220;//0x0dc
           recv_buf11[10] == 5;//代表mtu=1500,这是读到寄存器gevSCPSPacketSize的值
           //如果返回如此, recv_buf11[10] == 0x1f(31); recv_buf11[11] == 0xe4(228);代表mtu=8164,gevSCPSPacketSize 这是读到寄存器gevSCPSPacketSize的值

           if( recv_buf11[11] == 220&& recv_buf11[10] == 5)
           {
               mtu1500=true;
           }
    }

    if(mtu1500)
    {
                boost::array<uint8_t, 16>
            //buff8136= {0x42, 0x01, 0x00, 0x82, 0x00, 0x08,
            //0x01, 0x31, 0x00, 0x00, 0x0d,  0x04, 64, 0, 0x1f, 0x0c8};//8136
            buff8136= {0x42, 0x01, 0x00, 0x82, 0x00, 0x08,
            0x01, 0x31, 0x00, 0x00, 0x0d,  0x04, 64, 0, 0x1f, 0x0e4};//8164
                vis.Gvcp().m_sock.send_to(boost::asio::buffer(buff8136), *vis.Gvcp().m_it);

    }

//开始控制,向寄存器写入  acquisitionStart.SetValueAsync(1).ConfigureAwait(false)) as GvcpReply
    boost::array<uint8_t, 16>
        buff12= {0x42, 0x01, 0x00, 0x82, 0x00, 0x08,
        0x01, 0x32, 0x00, 0x03, 0x08, 4, 0, 0, 0, 1};
     vis.Gvcp().m_sock.send_to(boost::asio::buffer(buff12), *vis.Gvcp().m_it);
      boost::array<uint8_t, 12> recv_buf12;
 // boost::asio::ip::udp::endpoint sender_endpoint;
    if(vis.Gvcp().m_sock.receive_from(boost::asio::buffer(recv_buf12), sender_endpoint) == 12)
  {//这个在c#范例中化的时间很长,写寄存器开始acquisitionStart
        recv_buf12[11] == 0x01;
         //0 0 0 131 0 4 1 50 0 0 0 1
           //如果返回如此, recv_buf12[11] == 0x01;acquisitionStart 写入ok
    }

到这里,程序已经成功了,后面是读出图像并显示的过程,linux的第三方gil包和socket未达到预期,全部注释掉了。全部使用windows的东东,在通信和显示图像上。

   // 接收数据
               char buffer[9000];
              int len = sizeof(buffer);
              sockaddr_in from;
              int fromlen = sizeof(from);

             //   recvfrom(iFd, buffer, len, 0, (SOCKADDR*)&from, &fromlen);//应该有接受异常保护机制,这里如果异常,要继续向下达成202403181431

      //  GvspInfo.IsDecodingAsVersion2 = ((buffer[4] & 0xF0) >> 4) == 8;
            

                struct gvspinfo stu;//方式

            /*    if( ((buffer[4] & 0xF0) >> 4) != 8)
                {*/
                    stu.      BlockIDIndex =  2;
                    stu.    BlockIDLength =  2;
                    stu.    PacketIDIndex =  6;
                    stu.    PayloadOffset =  8;
                    stu.    TimeStampIndex = 12;
                    stu.    DataIdentifier = 0x03;
                    stu.    DataEndIdentifier =  0x02;
                //}else
                //{
                //    // GvspInfo.SetDecodingTypeParameter();
                //    stu.      BlockIDIndex =  8 ;
                //    stu.    BlockIDLength =  8 ;
                //    stu.    PacketIDIndex =  18 ;
                //    stu.    PayloadOffset =  20 ;
                //    stu.    TimeStampIndex =  24 ;
                //    stu.    DataIdentifier = 0x83 ;
                //    stu.    DataEndIdentifier =  0x82 ;
                //}
int packetID=-1;


 int frame=1;
  int jishu=-1;
  uint16_t nPartOfFrame=0;//一帧有619个8136
 //  uint16_t ceshi=0;
  COPYDATASTRUCT cds;

   uint8_t** buffer2 = new uint8_t*[2];

 /*  buffer2[0] = new char[stu.RawImageSize];
 buffer2[1] = new char[stu.RawImageSize];*/
     buffer2[0] = new uint8_t[2592*1944];
 buffer2[1] = new uint8_t[5038848];

 int  jiou=1;


 vis.Gvsp(). m_img.recreate(2592, 1944);

 recvfrom(iFd, buffer, 9000, 0, (SOCKADDR*)&Addr, &fromlen);
 nPartOfFrame = ntohs(((uint16_t*)&buffer)[3]);
    if(0==nPartOfFrame)
for(;;)
    
{

    int changdu=    recvfrom(iFd, buffer, 9000, 0, (SOCKADDR*)&Addr, &fromlen);//1472要不要也写一个分支处理程序?202403210919

    if(changdu==8164)
    {
    nPartOfFrame = ntohs(((uint16_t*)&buffer)[3]);//不进来,说明虽然设置8164,但实质只有8136收到buffer20240323
    }

    if(changdu!=8136)
        {
            std::cout<< "\recvpacketlenth: " << changdu<< "\frame: " << nPartOfFrame   <<std::endl;

//没有看到0包,说明0包没用202403311428
    continue;
    }
    if (changdu==8136)
    {

 nPartOfFrame = ntohs(((uint16_t*)&buffer)[3]);

      jiou=    frame%2;

            int zhenshidenPartOfFrame= ( nPartOfFrame-1)%619;

            if(jiou==1)
            {
                /* std::copy(std::begin(buffer)+8, std::end(buffer),   buffer2[1]+ zhenshidenPartOfFrame*8128);*/
                 std::copy(std::begin(buffer)+8, std::begin(buffer)+8136,   buffer2[1]+ zhenshidenPartOfFrame*8128);
                // std::copy(std::begin(buffer)+8, std::end(buffer)+8136,    view(vis.Gvsp().m_img).begin()+ zhenshidenPartOfFrame*8128);//太慢,应该丢失太多
            //     std::copy(std::begin(buffer)+8, std::end(buffer)+8136,   vis.Gvsp(). m_buffBIG.begin()+ zhenshidenPartOfFrame*8128);//速度可以

                //还是copydata好202403201554
            }
            else
            {
                 std::copy(std::begin(buffer)+8, std::begin(buffer)+8136,   buffer2[0]+ zhenshidenPartOfFrame*8128);
                /* std::copy(std::begin(buffer)+8, std::end(buffer),   buffer2[0]+ zhenshidenPartOfFrame*8128);*/

            }

            if(618==zhenshidenPartOfFrame)
            {

                frame++;

    cds.dwData=0;
                cds.cbData=5038848;//一帧500万像素
                //cds.cbData=4096;//一帧500万像素


                cds.lpData= buffer2[1];//这样写可以吗?

                if(jiou==0)
                    {
                        cds.lpData= buffer2[0];
                }


                //    cds.lpData=(PVOID)hdr->lpData;
                //    ::SendMessage(hWnd,WM_COPYDATA,NULL,(LPARAM)&cds);
                HWND hWnd=    ::    FindWindow(NULL,L"arrimg");//(LPCSTR),可以利用收声音的c#程序,现成的
                //HWND hWnd=    ::FindWindow(NULL,(LPCSTR)"arrimg");
                ::SendMessage(hWnd,WM_COPYDATA,NULL,(LPARAM)&cds);

            }

    }
}

最后加红的代码,是用sendmessage把图像丢出去,使用windows的WM_COPYDATA消息。

这个方法简单,如果你能存储数据流,像gil的png方式,存几幅图也是可以的,我试了,也是ok的。

要搞定,沉下心来,持之以恒。我可能讲的东西容量太大,你不要指望很快掌握,我吃不好,睡不好,花了整整一个月时间研究,针对这件事情,这还是在有图可希冀的情况下。

  • 13
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值