繁体   English   中英

Emgu.CV Object 标记

[英]Emgu.CV Object Marker

我建立了一个带有 2 个伺服系统和激光二极管的云台系统。 该系统由 Arduino Nano 控制。 通过在 C# 中使用 Emgu.CV,我创建了一个灰度图像并使用GrayImg.ThresholdBinaryInv将其转换为黑白图像。 我正在使用逆运动学计算,但激光二极管无法很好地标记 object。 我在哪里做错了? 图像坐标系和舵机坐标系不相同。 因此,我做了映射和缩放。 它应该可以工作,但激光二极管的精度不准确。

Arduino 代码

#include <Servo.h>

int Th1, Th2, tmp;
Servo M1;
Servo M2;
void setup() 
{
  Serial.begin(9600);
  pinMode(6,OUTPUT; // Laser Diode
  digitalWrite(6,0);
  Th1 = 0;
  Th2 = 0;
  M1.attach(3);
  M1.write(90);
  M2.attach(9);
  M2.write(90);
}

void loop() 
{
  delay(200); //sync issue only

  if(Serial.available()>=2)
  {
    Th1 = Serial.read(); //read only one byte
    Th2 = Serial.read();
    M1.write(Th1);
    M2.write(Th2);

    //Remove any extra worng reading
    while(Serial.available()) tmp = Serial.read();    
    
    // Run the robotic arm here. For testing, we will    
    digitalWrite(6,1);
    delay(500);
    digitalWrite(6,0);
    delay(500);
     
    //switch On or switch off a LED according to Th1 value


    
    //Serial.print('1'); // This tell the PC that Arduino is Ready for next angles
  }
}

C#代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.IO.Ports;
using System.Windows.Forms;
using Emgu.CV;
using Emgu.Util;
using Emgu.CV.Structure;

namespace ObjectMarker
{
    public partial class Form1 : Form
    {
        private Capture capture; 
        private Image<Bgr, Byte> IMG;
        private Image<Gray,Byte> blackWhite;
        private Image<Gray, Byte> GrayImg; 
        
        private int N, Xpx, Ypx; // N -> Number of non-black pixels
        private double Xcm, Ycm;
        private double myScale;
        private double Th1, Th2;
        static SerialPort _serialPort;
        public byte []Buff = new byte[2];
        
        public Form1() //Constructor of the Form1
        {
            InitializeComponent();
            //myScale = 65.0 / 480.0;
            myScale = 1.7 / 13;
             _serialPort = new SerialPort();
            _serialPort.PortName = "COM4";//Set your board COM
            _serialPort.BaudRate = 9600;
            _serialPort.Open();
        }
        

        private void processFrame(object sender, EventArgs e) // Most important function
        {                       //You're not connected any camera - null 
            if (capture == null)//very important to handel excption - capture - point of the camera
            {
                try
                {
                    capture = new Capture(1); //creatine a object 
                }
                catch (NullReferenceException excpt)
                {
                    MessageBox.Show(excpt.Message);
                }
            }

            IMG = capture.QueryFrame();// capture the current frame. Get an image.
         
            GrayImg = IMG.Convert<Gray, Byte>();
            blackWhite = GrayImg.ThresholdBinaryInv(new Gray(25),new Gray (255));
            
            Xpx = 0;
            Ypx = 0;
            N = 0;
       
            for (int i = 0; i < blackWhite.Width; i++) {
                for (int j = 0; j < blackWhite.Height; j++) {
                    if(blackWhite[j,i].Intensity > 128){
                        N++;
                        Xpx += i;
                    Ypx += j;
                    }
                }
            }
            
            if(N>0){

                Xpx = Xpx / N;
                Ypx = Ypx / N;
                
                Xpx = (blackWhite.Width / 2) - Xpx; //320 - xpx
                Ypx = Ypx - (blackWhite.Height / 2); // ypx - 240
    
                Xcm = Xpx * myScale;
                Ycm = Ypx * myScale;

                double d3 = 28; // Laser to wall dist. (?)
                double Zcm = 108; // Cam to wall dist.
                double d1 = 3.50; // Joint to joint dist.
                double l2 = 4.50; // Joint to laser dist. (?)


                textBox1.Text = Xcm.ToString();
                textBox2.Text = Ycm.ToString();
                textBox3.Text = N.ToString();
                textBox11.Text = Zcm.ToString();
                textBox12.Text = myScale.ToString();

                //Inverse Calculations

                double Px, Py, Pz,Diff = 0;
        
                // Mapping
                //Px = Zcm;
                Px = -1 * Zcm;
                Py = -1 * Xcm;
                Pz = Ycm + Diff; // The laptop has built-in camera and the pan-tilt above the keyboard so there's a distance between camera and pan-tilt system (laser diode)
                

                textBox8.Text = Px.ToString();
                textBox9.Text = Py.ToString();
                textBox10.Text = Pz.ToString();

                Th1 = Math.Atan((Py / Px));
                Th2 = Math.Atan((Math.Sin(Th1) * (Pz - d1)) / Py);
                

                //Th1 = Math.Atan(Ycm / Xcm);
                //Th2 = Math.Atan((Math.Sin(Th1) * (Zcm - d1)) / Ycm);
                
                textBox4.Text = Th1.ToString();
                textBox5.Text = Th2.ToString();

         
                Th1 = (Th1 * (180 / Math.PI));
                Th2 = (Th2 * (180 / Math.PI));
                Th1 += 90;
                Th2 += 90;

                textBox6.Text = Th1.ToString();
                textBox7.Text = Th2.ToString();

                label11.Text = trackBar1.Value.ToString();
                label12.Text = trackBar2.Value.ToString();
                
                Buff[0] = (byte)trackBar1.Value; //Th1
                Buff[1] = (byte)trackBar2.Value; //Th2
                _serialPort.Write(Buff,0,2);

            }
            else
            {
                textBox1.Text = "";
                textBox2.Text = "";
                textBox3.Text = N.ToString();

                Buff[0] = (byte)90; //Th1
                Buff[1] = (byte)90; //Th2
                _serialPort.Write(Buff, 0, 2);
            }
                
            
      
            try
            {
                
                imageBox1.Image = IMG;
                imageBox2.Image = GrayImg;
                imageBox3.Image = blackWhite;
                
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }



        private void button1_Click(object sender, EventArgs e)
        {
            //Application.Idle += processFrame; //Serial comm between arduino and computer
            timer1.Enabled = true;
            button1.Enabled = false;
            button2.Enabled = true;
        }

        private void button2_Click(object sender, EventArgs e)
        {
            //Application.Idle -= processFrame;
            timer1.Enabled = false;
            button1.Enabled = true;
            button2.Enabled = false;
        }    

        private void button3_Click(object sender, EventArgs e) // I measure the object size from paint. It gave me pixel size. Then I measure the real size of the image. Real size divided by pixel size gives scale.
        {
            IMG.Save("G:\\CurrentFrame" +  ".jpg");
        }
        void Timer1Tick(object sender, EventArgs e)
        {
            processFrame(sender,e);
        }       

        
    }
}

这个问题很难回答,因为有很多地方可能会出现错误。如果没有进一步的诊断和系统知识,几乎不可能给出明确的答案。 我建议您进行更多诊断,如果您仍然无法找到答案,请重新提出您的问题(或在您自己找到答案时关闭它)。

一些可能的错误来源(和诊断要点)可能是:

  • 在 Arduino 代码中,您在串行通信的前两个字节之后丢弃任何内容。 为什么会有额外的字节? 您确定多余的字节是垃圾,相反,前两个字节是正确的吗?
  • 在 C# 坐标映射中,您执行坐标的平移。 您确定系统完全平行轴吗? 仅仅几度的误差很快就会增加。 您可能需要添加旋转变换。
  • 您的 C# 代码返回伺服的角度(以度为单位)。 这可能是负数,或高于 255,因此将其转换为字节可能会在溢出时导致将(完全)错误的值传递给 Arduino。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM