搜索
bottom↓
回复: 54

基于摄像头和一字线激光器的3D扫描仪

[复制链接]

出0入0汤圆

发表于 2012-2-21 15:53:06 | 显示全部楼层 |阅读模式
一直都在打算做个3D扫描仪,只是比较懒,又没有毅力,写下此帖以做鞭策。
这种扫描仪以前有人发过:
[原创+开源]DIY低成本3D激光扫描测距仪(激光雷达)
http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=5247845
按照这种原理咱也DIY一个。
摄像头采用了最普通的,价值25大洋,激光器在淘宝上买的,50元左右。
旋转部分准备用减速电机+计数器,单片机控制,S52。
上位机软件用delphi7来写,用的比较熟悉了。
先上几张图

(原文件名:一字线.JPG)


(原文件名:一字线激光器.JPG)


(原文件名:整体.JPG)


(原文件名:整图2.JPG)


(原文件名:界面.JPG)

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

 楼主| 发表于 2012-2-22 08:29:23 | 显示全部楼层
刚取得的一些数据,还没有做标定。

(原文件名:数据.JPG)

出0入0汤圆

发表于 2012-3-25 23:30:49 | 显示全部楼层
我也想搞一个玩玩,有3D的还原图像么?

出0入0汤圆

发表于 2012-3-29 23:20:22 | 显示全部楼层
这个有点意思

出0入0汤圆

发表于 2012-3-31 11:43:20 | 显示全部楼层
楼主  牛逼啊   佩服

出0入0汤圆

 楼主| 发表于 2012-4-21 18:51:09 | 显示全部楼层
说来惭愧,最近工作挺忙,暂时放下了。保证有进展一定来更新。

出0入0汤圆

发表于 2012-4-23 11:16:22 | 显示全部楼层
效果如何啊,好的话我也试试

出0入0汤圆

发表于 2012-5-11 13:43:16 | 显示全部楼层
跟帖~~ 学习 一字激光器 和摄像头我都买好了~~  软件方面 还得从0开始学啊 ~~    我用的 VC++

出0入0汤圆

发表于 2012-5-17 13:26:31 | 显示全部楼层
mark,一直在关注。

出0入0汤圆

 楼主| 发表于 2012-6-6 11:18:24 | 显示全部楼层
谢谢大家的关注。
拖了这么长时间,终于做出了1.0版,呵呵。
先发个点云图,其他的陆续发。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2012-6-6 11:42:55 | 显示全部楼层
硬件组成。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2012-6-6 12:36:10 | 显示全部楼层
不用顶,不用问,直接放源代码。不用下载,直接拷贝。
业余水平,欢迎拍砖。
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs,videocap, StdCtrls,jpeg, ExtCtrls, ExtDlgs, OleCtrls,
  MSCommLib_TLB, Mask;

type
  TForm1 = class(TForm)
    Openvideo: TButton;
    Closevideo: TButton;
    Button1: TButton;
    Label1: TLabel;
    Panel1: TPanel;
    Image1: TImage;
    Button2: TButton;
    Label2: TLabel;
    ScrollBar1: TScrollBar;
    Edit2: TEdit;
    Edit3: TEdit;
    Button3: TButton;
    Button4: TButton;
    MSComm1: TMSComm;
    Edit4: TEdit;
    Label3: TLabel;
    Button5: TButton;
    Image2: TImage;
    Memo1: TMemo;
    Button6: TButton;
    Button7: TButton;
    Button8: TButton;
    procedure Button1Click(Sender: TObject);
    procedure OpenvideoClick(Sender: TObject);
    procedure ClosevideoClick(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormCreate(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
    procedure MSComm1Comm(Sender: TObject);
    procedure Button5Click(Sender: TObject);
    procedure Button7Click(Sender: TObject);
    procedure Button6Click(Sender: TObject);
    procedure Button8Click(Sender: TObject);





  private
    { Private declarations }
  public

    { Public declarations }
  end;

var
  Form1: TForm1;
  //定义捕获窗句柄
  hWndC : THandle;
  jishu:integer;
  Z:integer;
  positio:string;
type
  THDFunction = function(I:integer;s:string):integer; stdcall ;

  PVIDEOHDR = ^TVIDEOHDR;
  TVIDEOHDR = record
    lpData:pByte;                 // pointer to locked data buffer
    dwBufferLength:DWORD;         // Length of data buffer
    dwBytesUsed:DWORD;            // Bytes actually used
    dwTimeCaptured:DWORD;         // Milliseconds from start of stream
    dwUser:DWORD;                 // for client's use
    dwFlags:DWORD;                // assorted flags (see defines)
    dwReserved: array [0..4] of DWORD;    // reserved for driver
  end;

  TCAPVIDEOSTREAMCALLBACK = function(hWnd:HWND; lpVHdr:PVIDEOHDR):LongInt; stdcall;


  const WM_CAP_START = WM_USER;
  const WM_CAP_STOP = WM_CAP_START + 68;
  const WM_CAP_DRIVER_CONNECT = WM_CAP_START + 10;
  const WM_CAP_DRIVER_DISCONNECT = WM_CAP_START + 11;
  const WM_CAP_SAVEDIB = WM_CAP_START + 25;
  const WM_CAP_GRAB_FRAME = WM_CAP_START + 60;
  const WM_CAP_SEQUENCE = WM_CAP_START + 62;
  const WM_CAP_FILE_SET_CAPTURE_FILEA = WM_CAP_START + 20;
  const WM_CAP_SEQUENCE_NOFILE =WM_CAP_START+ 63;
  const WM_CAP_SET_OVERLAY =WM_CAP_START+ 51;
  const WM_CAP_SET_PREVIEW =WM_CAP_START+ 50;
  const WM_CAP_SET_CALLBACK_VIDEOSTREAM = WM_CAP_START +6;
  const WM_CAP_SET_CALLBACK_ERROR=WM_CAP_START +2;
  const WM_CAP_SET_CALLBACK_STATUSA= WM_CAP_START +3;
  const WM_CAP_SET_CALLBACK_FRAME= WM_CAP_START +5;
  const WM_CAP_SET_SCALE=WM_CAP_START+ 53;
  const WM_CAP_SET_PREVIEWRATE=WM_CAP_START+ 52;
  const WM_CAP_GET_VIDEOFORMAT  = WM_CAP_START+  44;

  

implementation

{$R *.dfm}

function capCreateCaptureWindowA(lpszWindowName : PCHAR; dwStyle : longint; x : integer;
y : integer;nWidth : integer;nHeight : integer;ParentWin : HWND;
nId : integer): HWND;STDCALL EXTERNAL 'AVICAP32.DLL';




procedure TForm1.Button1Click(Sender: TObject);
begin
  close;
end;

function FrameCallBack(hWnd:HWND;lpVHdr: PVideoHDR):LongInt; stdcall;
var
  bit: TBitmap;
  info: TBitmapInfo;
  p1,p2:pbytearray;
  x,y:integer;
  rx,ry,ra:real;
  Gray:integer;
  ltmp,lx,ly:integer;
  lianxu:boolean;
  shuchu:string;
begin

  if (positio=form1.Label3.Caption) or (strtoint(form1.Label3.Caption )<67)   then exit  ;
  positio:=form1.Label3.Caption   ;
  SendMessage(hwndc, WM_CAP_GET_VIDEOFORMAT, Wparam(sizeof(info)), LPARAM(@info));
  if info.bmiHeader.BiCompression = bi_RGB then
  begin
    bit := TBitmap.Create;
    try
      with bit, info.bmiHeader do
      begin
        PixelFormat := pf24bit;
        Width := biWidth;
        Height := biHeight;
        setDiBits(canvas.handle, handle, 0, biheight,
          lpVHdr^.lpData, info, DIB_RGB_COLORS);

        form1.Image1.Width := info.bmiHeader.biwidth;
        form1.Image1.Height := info.bmiHeader.biheight;
        form1.Image1.Picture.Assign(bit);
      end;
    finally
      bit.Free;
    end;
    //以上是捕获到image1中的代码



     //图像处理开始    ××××××核心×××××××××
        ltmp:=0;
        ly:=0;
        lx:=0;
        rx:=0;
        ry:=0;
        ra:=(strtoint(form1.Label3.Caption)-64)*0.72;
        shuchu:='';
        for y:=0 to form1.Image1.Picture.bitmap.Height -1 do
          begin
            jishu:=0;
            p1:=form1.Image1.Picture.bitmap.ScanLine [y];
            for x:=1 to  form1.Image1.Picture.bitmap.Width -1 do
              begin
                if (p1[3*x+2]>(form1.ScrollBar1.Position *2.54)) and (x<form1.Image1.Picture.bitmap.Width -1)   then      //二值化
                  begin
                    lianxu:=true;
                    ltmp:=ltmp+x;
                    jishu:=jishu+1;
                    //rx:=1468.9-206.3*ln(lx);
                    //ry:=(240-ly)/(lx+190)*150;
                    //if rx<400 then form1.Memo1.Lines.Add (formatfloat('0.0',rx*cos(ra/180*pi))+' '+formatfloat('0.0',ry)+' '+formatfloat('0.0',rx*sin(ra/180*pi))) ;
                    //p1[3*x]:=255;     // 蓝
                    //p1[3*x+1]:=255;   //  绿
                    //p1[3*x+2]:=255;   //  红
                  end
                else
                  begin
                    if lianxu then
                      begin
                        lianxu:=false;
                        rx:=1468.9-206.3*ln(ltmp/jishu);
                        ry:=(240-y)/(ltmp/jishu+190)*150;
                        form1.Memo1.Lines.Add (formatfloat('0.0',rx*cos(ra/180*pi))+' '+formatfloat('0.0',ry)+' '+formatfloat('0.0',rx*sin(ra/180*pi))) ;
                        p1[3*x]:=255;     // 蓝
                        p1[3*x+1]:=255;   //  绿
                        p1[3*x+2]:=255;   //  红
                        jishu:=0;
                        ltmp:=0;
                      end
                    else
                      begin
                        p1[3*x]:=0;
                        p1[3*x+1]:=0;
                        p1[3*x+2]:=0;
                      end;
                  end;
              end;


          end;
        //if lx=0 then lx:=800;
        //rx:=1468.9-206.3*ln(lx);
        //ry:=(240-ly)/(lx+190)*150;
        //form1.Label1.Caption :=formatfloat('0.0',rx)+' '+formatfloat('0.0',ry)+' '+inttostr(ltmp);


    //图像处理结束


    //图像拷贝至image2
    form1.Image2.Picture.Assign(form1.Image1.Picture.Bitmap );

    form1.mscomm1.Output:=char(65);
  end;
end;

procedure TForm1.OpenvideoClick(Sender: TObject);
begin
hWndC := capCreateCaptureWindowA('My Own Capture Window',WS_CHILD or WS_VISIBLE ,Panel1.Left,Panel1.Top,Panel1.Width,Panel1.Height,Form1.Handle,0);
if hWndC <> 0 then
begin
SendMessage(hWndC, WM_CAP_SET_CALLBACK_VIDEOSTREAM, 0, 0);
SendMessage(hWndC, WM_CAP_SET_CALLBACK_ERROR, 0, 0);
SendMessage(hWndC, WM_CAP_SET_CALLBACK_STATUSA, 0, 0);
SendMessage(hWndC, WM_CAP_DRIVER_CONNECT, 0, 0);
SendMessage(hWndC, WM_CAP_SET_SCALE, 1, 0);
SendMessage(hWndC, WM_CAP_SET_PREVIEWRATE, 66, 0);
SendMessage(hWndC, WM_CAP_SET_PREVIEW, 1, 0);
SendMessage(hwndc, WM_CAP_SET_CALLBACK_FRAME, 0,LPARAM( @FrameCallBack)) ;    //回调函数 必须装SG310摄像头驱动


end;

end;

procedure TForm1.ClosevideoClick(Sender: TObject);
begin
if hWndC <> 0 then begin
SendMessage(hWndC, WM_CAP_DRIVER_DISCONNECT, 0, 0);
hWndC := 0;
end;


end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  if hWndC <> 0 then
    begin
    SendMessage(hWndC, WM_CAP_DRIVER_DISCONNECT, 0, 0);
    end;
  if mscomm1.PortOpen  then
    begin
      mscomm1.PortOpen := false;
      mscomm1.DTREnable :=false;
      mscomm1.RTSEnable :=false;
    end;
end;


procedure TForm1.FormCreate(Sender: TObject);
begin
  jishu:=0;
  z:=strtoint(label3.Caption  );
  positio:=form1.Label3.Caption   ;
  //初始化串口
  edit2.Text :=mscomm1.Settings ;
  edit3.Text :=inttostr(mscomm1.CommPort );
  mscomm1.InBufferSize := 1024;             //接收缓冲区
  mscomm1.OutBufferSize := 1024;             //发送缓冲区
  mscomm1.InputMode := 1;       //接收模式    0:文本 1:二进制
  mscomm1.InputLen := 0;                     //一次读取所有数据
  mscomm1.SThreshold := 0;                   //一次发送所有数据
  mscomm1.InBufferCount := 0;               //清空读取缓冲区
  mscomm1.OutBufferCount := 0;               //清空发送缓冲区

  MSComm1.RThreshold :=1;               //设置接收多少字节开产生oncomm事件  太频繁可能会使程序失去响应

end;


procedure TForm1.Button2Click(Sender: TObject);
begin
  label3.Caption  :=inttostr(strtoint(label3.Caption  )+1);
  memo1.Clear ;
end;

procedure TForm1.Button3Click(Sender: TObject);
begin

  mscomm1.CommPort := strtoint(edit3.Text );                     //指定端口
  mscomm1.Settings := edit2.Text;         //其它参数

  mscomm1.PortOpen:=true ;
  mscomm1.DTREnable :=true;
  mscomm1.RTSEnable :=true;
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
  if mscomm1.PortOpen  then
    begin
      mscomm1.PortOpen := false;
      mscomm1.DTREnable :=false;
      mscomm1.RTSEnable :=false;
    end;
end;

procedure TForm1.MSComm1Comm(Sender: TObject);
var
  filenrc :char;
  buffer :olevariant;
  s1:string;
  c :char;
  reData:array of Variant;
  restr:string;
  i:integer;
begin
  //buffer:= form1.MSComm1.commevent;
  //form1.memDisplay.Lines.Add (buffer) ;
  case form1.mscomm1.commEvent of
    comEvSend:
      begin
      end;
    comEvReceive:
        begin
          reData:= mscomm1.Input  ;
          mscomm1.InBufferCount :=0;
          restr:='';
          for i:=0 to vararrayhighbound(redata,1) do
            begin
              restr:=restr+ inttostr(redata[i]);
            end;
          label3.Caption :=restr;
          //mscomm1.InBufferCount :=0;     //在此清空缓冲区会丢数据

        end;

   end;

end;

procedure TForm1.Button5Click(Sender: TObject);
var
  Tchar:char;
  Tbuffer :olevariant;
begin

  label1.Caption := inttostr(  strtoint(edit4.Text ));
  mscomm1.Output:=char(strtoint(edit4.Text )+64);

end;

procedure TForm1.Button7Click(Sender: TObject);
begin
  mscomm1.Output:=char(62);

end;

procedure TForm1.Button6Click(Sender: TObject);
begin
  mscomm1.Output:=char(66);
end;

procedure TForm1.Button8Click(Sender: TObject);
begin
  form1.Memo1.Lines.SaveToFile('d:\haha.xyz');
end;



end.

出0入0汤圆

 楼主| 发表于 2012-6-6 12:38:32 | 显示全部楼层
还有单片机的源代码,不懂C,只能用汇编写的。
    ;这是一个使用单片机通过NUL2003驱动步进电机程序.
    ;步进电机: 5伏,500MA/STEP,四线四拍.
    ;将步进电机的A B C D四个绕组连接到"步进电机"的A,B,C,D,将公用抽头并接在VCC上.
            BUFF_STEP   EQU   31H
                POSITION  EQU  32H
            SW1  BIT   P1.5
            SW2  BIT         P1.6
            SMG1 EQU P1.0        ;定义数码管阳级控制脚,第一个
            SMG2 EQU P1.1        ;定义数码管阳级控制脚,第二个

            ORG  000h
            JMP  START
               
        ORG 0023H
        AJMP RECEIVE          ;跳转到接收中断入口
;----------------------------------------
;-----------数据存放----------------------
ORG 0100H
TABLE:        DB 0C0h,0F9H,0A4H,0b0H,99H,92H,82H,0F8H,80H,90H,88H,83H,0C6H,0A1H,86H,8EH;表:共阳数码管 0-9 A-F

TAB_CW:  DB   11111011B,11101011B,11101111B,11100111B,11110111B,11010111B,11011111B,11011011B     ;正转相序        a橙  b黄  c黑   d棕   com红
TAB_CCW: DB   11011111B,11010111B,11110111B,11100111B,11101111B,11101011B,11111011B,11011011B    ;反转相序


;-----------------------------------------------
    ORG  300H
START:

        MOV   BUFF_STEP,#00H
    MOV   P0,#0fFh          ;初始化MCU端口
    MOV   P1,#0ffh
    MOV   P3,#0ffh
    MOV   P2,#0ffH
    MOV   A,#00H           ;初始化寄存器
    MOV   PSW,#00H
    MOV   IE,#00H
    MOV   SP,#80H
        MOV         POSITION,#40H
        MOV TMOD,#20H         ;T1工作方式2
    MOV TH1,#0FDH         ;波特率9600
    MOV SCON,#50H         ;传口工作方式1,允许中断接受
    SETB EA               ;打开总中断
    SETB ES               ;打开串口中断
    SETB TR1              ;打开定时器1
       

MAIN:

        MOV A,POSITION
        LCALL DISPLAY
        LJMP MAIN
       


RECEIVE:
        CLR RI
        MOV A,SBUF            ;串口接收数据
                MOV R0,A
PANDUAN:MOV A,R0
                CJNE A,#40H,ZHUAN ;判断A是否等于40H,等于则停止转动,程序返回。
                LJMP TING
ZHUAN:        ;转动
                JC ZZHUAN
                ;反转
                LCALL FZ
                INC POSITION
                DEC R0
                LJMP PANDUAN
ZZHUAN:                ;正转
                LCALL ZZ
                DEC POSITION
                INC R0
                LJMP PANDUAN

TING:        MOV A,POSITION  ;停止转动后返回当前位置
        MOV SBUF,A            ;将数据传送给计算机
        JNB TI,$
        CLR TI
        RETI
;正转8拍子程序=======================      
ZZ:
        MOV  DPTR,#TAB_CW
        MOV   A,BUFF_STEP
    MOVC  A,@A+DPTR
       
    MOV   P2,A
    MOV   P3,A
        MOV A,POSITION
        LCALL DISPLAY

    INC   BUFF_STEP
    MOV   A,BUFF_STEP
    CJNE  A,#08H,ZZ
    MOV   BUFF_STEP,#00H
    RET
;反转8拍子程序===================
FZ:
        MOV  DPTR,#TAB_CCW
        MOV   A,BUFF_STEP
    MOVC  A,@A+DPTR
       
    MOV   P2,A
    MOV   P3,A
        MOV  A,POSITION
        LCALL DISPLAY

    INC   BUFF_STEP
    MOV   A,BUFF_STEP
    CJNE  A,#08H,FZ
    MOV   BUFF_STEP,#00H
    RET



;显示A子程序==================
DISPLAY:
        PUSH ACC

        MOV DPTR,#TABLE        ;数码管显示子程序
        MOV B,#16
        DIV AB
        CLR SMG1        ;选择十位数码管       
        MOVC A,@A+DPTR        ;查表输出定义好的数码管段值与P0口,显示相应的0-9
        MOV P0,A
        LCALL DELAY        ;延时,停留一会,让人眼感触到它的亮度
        MOV P0,#0FFH        ;清除数码管显示,因是共阳型,所以不是0
        SETB SMG1        ;关闭十位数码管

        CLR SMG2        ;选择个位数码管
        MOV A,B                ;个位显示
        MOVC A,@A+DPTR        ;查表输出定义好的数码管段值与P0口,显示相应的0-9
        MOV P0,A
        LCALL DELAY        ;延时,停留一会,让人眼感触到它的亮度
        MOV P0,#0FFH        ;清除数码管显示,因是共阳型,所以不是0
        SETB SMG2        ;关闭个位数码管
        POP ACC
        RET

;延时子程序=================================
DELAY:        
                MOV   R6,#4
DEL0:   MOV   R7,#255
        DJNZ  R7,$
        DJNZ  R6,DEL0  

        RET



         
        END


出0入0汤圆

 楼主| 发表于 2012-6-6 12:46:03 | 显示全部楼层
待改进的地方还有很多,目前用memo控件显示数据,速度很受影响,如果不显示数据只是扫描的话速度要快N倍。
另外目前步进电机每次转8拍,显得点云间距有些过大,还可以再调整。
支架有些过于简陋,呵呵,是个八宝粥罐子,内含步进电机。
控制板应该搞个盒子装起来。
先这样,做为业余人士的原理验证机,俺已经很满足了,嘿嘿

出0入0汤圆

 楼主| 发表于 2012-6-6 14:13:17 | 显示全部楼层
再上一张效果图。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2012-6-6 15:12:35 | 显示全部楼层
本帖最后由 lf751117 于 2012-6-6 15:31 编辑

你这只是平面扫描巴?并不是三维扫描。

出0入0汤圆

 楼主| 发表于 2012-6-6 16:18:54 | 显示全部楼层
lf751117 发表于 2012-6-6 15:12
你这只是平面扫描巴?并不是三维扫描。

虽然是简单了些,但确实是三维扫描。
因为只是从一个角度去扫的,点云并不完整。完整的点云数据需要多个角度扫描然后拼接。
继续上图:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2012-6-6 16:40:11 | 显示全部楼层
能加你QQ不?我最近也在研究这个激光三维扫描,可是有些问题搞不懂,要请教你!我的QQ:17755037

出0入0汤圆

 楼主| 发表于 2012-6-6 16:55:56 | 显示全部楼层
邮箱吧 wongjan@139.com
QQ不怎么用的。
在这个帖子大家讨论最好吧。

出0入0汤圆

发表于 2012-6-6 17:10:59 | 显示全部楼层
我知道和被测对象之间距离可以根据成像后像素X坐标值来辨别,而被测对象的实际高度是怎么测得的?你有没有可以算出XYZ各值可直接套用的公式?

出0入0汤圆

发表于 2012-6-6 17:43:27 | 显示全部楼层
mark学习了

出0入0汤圆

 楼主| 发表于 2012-6-7 09:19:15 | 显示全部楼层
lf751117 发表于 2012-6-6 17:10
我知道和被测对象之间距离可以根据成像后像素X坐标值来辨别,而被测对象的实际高度是怎么测得的?你有没有 ...

代码里有这么一段,就是计算xyz三个坐标值的。
                        rx:=1468.9-206.3*ln(ltmp/jishu);
                        ry:=(240-y)/(ltmp/jishu+190)*150;
                        form1.Memo1.Lines.Add (formatfloat('0.0',rx*cos(ra/180*pi))+' '+formatfloat('0.0',ry)+' '+formatfloat('0.0',rx*sin(ra/180*pi))) ;
我开始打印了一张坐标纸,放在激光所形成的平面上,摄像头采集到如下图片:

然后依次采集x坐标的点,摄像头像素点和实际x坐标间归纳出一个公式,即
实际x坐标:=1468.9-206.3*ln(像素点x坐标);     
   实际y坐标:=(240-像素y坐标)/(像素点x坐标+190)*150;

有了这两个坐标值,根据扫描仪目前的角度,就可以用三角函数算出实际xyz坐标。

这种算法比较简单,但精度低,只能算是业余算法。

我做这个能简化的就简化了,以后有时间能优化的就优化。


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2012-6-7 09:23:05 | 显示全部楼层
本帖最后由 wongjan 于 2012-6-7 09:25 编辑

沿一条水平线采集数据,然后导入excel,生成散布图,再添加一条趋势线,找一个拟合程度最好的,显示出公式,就ok了。
下面是我采集的数据:
X像素值        实际x坐标
474        1
452        2
429        3
406        4
386        5
367        6
349        7
331        8
315        9
300        10
287        11
271        12
259        13
248        14
234        15
225        16
215        17
205        18
195        19
187        20
177        21
169        22
161        23
154        24
150        25
142        26
137        27
129        28
123        29
117        30
111        31
105        32
100        33
95        34
90        35
86        36
82        37
77        38
73        39
68        40

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2012-6-7 10:59:07 | 显示全部楼层
要去翻数学书拉,都忘光拉。。。。。。。。。。对数,好晕!

出0入0汤圆

发表于 2012-6-7 14:17:58 | 显示全部楼层
本帖最后由 lf751117 于 2012-6-7 14:40 编辑

http://www.ourdev.cn/forum.php?mod=viewthread&tid=5247845
这篇里都根据焦距来算,我觉得是不是应该用像距?凸透镜到感光芯片的距离应该是像距巴?
而且像距不等于焦距阿。

出0入0汤圆

发表于 2012-6-7 16:07:00 | 显示全部楼层
赞一个

出0入0汤圆

 楼主| 发表于 2012-6-8 08:19:44 | 显示全部楼层
楼主头像!哈哈!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2012-6-8 08:23:28 | 显示全部楼层
lf751117 发表于 2012-6-7 14:17
http://www.ourdev.cn/forum.php?mod=viewthread&tid=5247845
这篇里都根据焦距来算,我觉得是不是应该用像 ...

这篇文章我之前也看过,不过说实话,有很多东西没看懂,里面涉及到的很多数学知识理解不了。以前上学时就挺头疼数学的。
我用了比较简单的方法。
核心是找到摄像头的像素点对应的实际空间的xyz坐标。

出0入0汤圆

发表于 2012-6-18 21:48:59 | 显示全部楼层
牛X,我两个月前也在开始筹备做这个了,准备在这个暑假做下,希望能得到大哥的帮助

出0入0汤圆

发表于 2012-11-6 09:38:40 | 显示全部楼层
不知道楼主进展怎么样了。最近学校的事弄完了,想学学看。

出0入0汤圆

发表于 2012-11-6 10:03:15 | 显示全部楼层
求激光头链接,我看了下,大部分光线分布不均匀。

出0入0汤圆

发表于 2012-11-6 11:06:32 | 显示全部楼层
不错,希望早日赶上csk陈老哥。

出0入0汤圆

发表于 2012-11-6 12:29:27 | 显示全部楼层
mark一下

出0入0汤圆

发表于 2012-11-8 09:23:15 | 显示全部楼层
wongjan 发表于 2012-2-22 08:29
刚取得的一些数据,还没有做标定。

(原文件名:数据.JPG)

LZ大神,你的界面是用什么做的??

出0入0汤圆

 楼主| 发表于 2012-11-8 12:48:22 | 显示全部楼层
上位机程序用delphi开发的。下位机用的keil。
得到数据存成xyz格式文件,然后用solidworks可以编辑。
开发过程中用excel分析。

出0入0汤圆

发表于 2012-11-14 22:47:58 | 显示全部楼层
SendMessage(hwndc, WM_CAP_GET_VIDEOFORMAT, Wparam(sizeof(info)), LPARAM(@info));
请问上面的这句是不是声明一个回调函数呀?
还有下面的这个判断语句是什么意思啊?  if info.bmiHeader.BiCompression = bi_RGB then
应该是这样吧
nfo.bmiHeader.BiCompression := bi_RGB then;
delphi刚学,请指教  谢谢啦

出0入0汤圆

 楼主| 发表于 2012-11-15 16:59:54 | 显示全部楼层
是声名回调函数,捕获视频后处理。
=用在if语句里是判断两边是不是相等。
:=是用来赋值的。
以上发的代码是直接拷贝的,我编译通过了。应该不会有错误。

出0入0汤圆

发表于 2012-11-17 15:08:03 | 显示全部楼层
wongjan 发表于 2012-11-15 16:59
是声名回调函数,捕获视频后处理。
=用在if语句里是判断两边是不是相等。
:=是用来赋值的。

因为没有整个工程,所以有些控件的是指不知道,无法整个工程编译。
研究了几天楼主的东西,info.bmiHeader.BiCompression = bi_RGB  你这句话应该是判断位图是否压缩了的标志。bi_RGB 为非压缩
但是看不太明白,不知道从摄像头获取的图片转换为位图后是否压缩了,没有设置应该不会被压缩吧。但是使用了
if info.bmiHeader.BiCompression = bi_RGB then
  begin
//info.bmiHeader.BiCompression := bi_RGB;  我加的 如果不要if 判断info.bmiHeader.BiCompression = bi_RGB    直接设置为info.bmiHeader.BiCompression := bi_RGB;
    bit := TBitmap.Create;
    try
      with bit, info.bmiHeader do
      begin
效果如下


如果既不判断也不设置info.bmiHeader.BiCompression = bi_RGB
则是


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2012-11-17 15:41:25 | 显示全部楼层
wongjan 发表于 2012-11-15 16:59
是声名回调函数,捕获视频后处理。
=用在if语句里是判断两边是不是相等。
:=是用来赋值的。

如果方便的话能不能把你的工程发一份我,对这部分图像处理比较感兴趣。
顺便上传一本书,很不凑的,在坛子里面淘的





由于pdf太大无法上传,不好意思,
如果要的话留下邮箱。估计是权限不够

下面是我的工程中间的处理部分是引用的您的,其余的是照网上写的,都差不多,我没有加串口,
感觉图像显示不正确,不知道引用您的是不是对的。



过段时间打算用摄像头试试扫描条形码,不知道您对这有什么看法,初步查了下资料,貌似用
这个做的不多,手机上的蛮多。
我的邮箱 abcfanyuan@vip.qq.com 谢谢。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2012-11-18 00:18:48 | 显示全部楼层
本帖最后由 abcfanyuan 于 2012-11-18 02:22 编辑

请问你的摄像头用的是什么型号?我的是usb免驱动的,但是查不到输出图片的格式,貌似是YUY2,你的是什么格式的图片?
我用你的处理函数的时候当用了if info.bmiHeader.BiCompression = bi_RGB then时调试时无法进入到if后面。估计是格式不对
我应该要将YUY2 的转换为REB24吧。
其中biBitCount=16.biCompression=844715353

出0入0汤圆

 楼主| 发表于 2012-11-22 12:48:47 | 显示全部楼层
abcfanyuan 发表于 2012-11-6 10:03
求激光头链接,我看了下,大部分光线分布不均匀。

某宝搜一字线激光器。我这个50元左右,也不是很好,不过焦距可以调,也就是线粗细是可以调整的。
我感觉没必要用太好的,因为摄像头采集的图像也不会有太高的分辨率。
我这个3D扫描仪误差有几个mm,只能当玩具用。

出0入0汤圆

 楼主| 发表于 2012-11-22 12:57:30 | 显示全部楼层
abcfanyuan 发表于 2012-11-17 15:08
因为没有整个工程,所以有些控件的是指不知道,无法整个工程编译。
研究了几天楼主的东西,info.bmiHeade ...

关于图像捕获这部分代码都是从网上copy下来的,vfw捕获。

这里强调一点,我发现用免驱动的摄像头,在windows里可以用,但是在程序里vfw捕获不了,需要装驱动。

我是绕了半天才发现的,最后用驱动精灵装了个驱动。也可以拆开看看里面芯片,然后下载相应的驱动。

实话说,我对此视频捕获的原理研究的也不是很透彻,因为捕获完后面的算法才是关键。
捕获到image控件中之后,用scanline读到一个数组,然后当数组处理就可以了。

至于整个工程,我回头整理一下,最近在搞别的项目玩,呵呵

那本Delphi数字图像处理及高级应用.pdf确实不错,几年前就有了,呵呵。我好多代码就是参照上面来的。

出0入0汤圆

 楼主| 发表于 2012-11-24 14:55:19 | 显示全部楼层
delphi的源代码。
现在电脑上的delphi程序有些问题,这部分代码不敢保证是有效的。仅供参考吧。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2012-11-24 23:41:34 | 显示全部楼层
wongjan 发表于 2012-11-24 14:55
delphi的源代码。
现在电脑上的delphi程序有些问题,这部分代码不敢保证是有效的。仅供参考吧。 ...

谢谢啦!看看

出0入0汤圆

发表于 2013-3-23 21:36:56 | 显示全部楼层
大神,你的扫描图能应用到精雕机上吗

出0入0汤圆

发表于 2013-3-23 23:56:14 | 显示全部楼层
mark!!!!!!!!!!

出0入0汤圆

发表于 2013-4-11 15:23:47 | 显示全部楼层
好东西,慢慢啃,DELPHI早忘光了,研究看看VBA能否搞定

出0入0汤圆

发表于 2013-4-12 09:08:07 | 显示全部楼层
不错的的激光3d处理

出0入0汤圆

 楼主| 发表于 2013-5-17 11:50:47 | 显示全部楼层
LONG.214214 发表于 2013-3-23 21:36
大神,你的扫描图能应用到精雕机上吗

恐怕是不行,精度太低了,只能当玩具。

出0入0汤圆

发表于 2013-5-17 12:38:07 | 显示全部楼层
mark一下回去研究研究
感谢楼主共享啊

出0入0汤圆

发表于 2013-5-18 23:37:46 | 显示全部楼层
好久没有弄这个了,没事做又来捣鼓下。之前做得差不多了,可以得到数据。并且对数据进行二值化。但是我发现你仅仅是对RGB中的红色作为分辨
特征,如果遇到背景是白色或者是亮色时当阀值提高时会使激光也消失。不知道是不是我买的激光不太好

出0入0汤圆

发表于 2013-5-18 23:39:46 | 显示全部楼层
还有个问题,就是你的那个摄像头和激光的角度是个什么关系呢?我计算了下,应该和他们的角度有关吧
是不是你用那个坐标纸求得一个拟合公式就是为了省去计算角度方面的?

出0入0汤圆

发表于 2013-5-19 02:03:29 | 显示全部楼层
mark!!!!!!

出0入0汤圆

 楼主| 发表于 2013-5-21 09:46:57 | 显示全部楼层
abcfanyuan 发表于 2013-5-18 23:37
好久没有弄这个了,没事做又来捣鼓下。之前做得差不多了,可以得到数据。并且对数据进行二值化。但是我发现 ...

周边不应该有强光源干扰,必要的话可以在摄像头加个滤镜(剪张软盘芯就可以)。

出0入0汤圆

 楼主| 发表于 2013-5-21 09:49:40 | 显示全部楼层
abcfanyuan 发表于 2013-5-18 23:39
还有个问题,就是你的那个摄像头和激光的角度是个什么关系呢?我计算了下,应该和他们的角度有关吧
是不是 ...

是的,因为摄像头的焦距、镜头参数都不知道,所以用了张坐标纸,用excel拟合出了个公式。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-14 05:50

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表