这才是我当年写出的一个比较烂的程序 p*)I QM<B
V.*y_=i8t
Main2.bas >3pT).wH|M
lC`w}0p
Attribute VB_Name = "SubMain" M@P%k`6C
Option Explicit RwYFBc
K~2sX>l
'采集文件与临时文件 $(+xhn(O
Public Const TmpFile As String = "d:\30-0600.dat" *^Ges;5$"
'已有数据:30-0600.dat /30日早6点进车与6:30出车头 [ZC\8tP`V
,Q3OQ[Nmh
Public fStatus As Long, hFile As Long, bytesRW As Long, lptrFile As Long 4c95G^dZ
Public hBCFile As Long '记录采集参数的文件 G;iH.rCH
Public Const TmpBMP As String = "d:\1.bmp" ;']u}Nh
Public hTmpFile As Long }mzd23^W>P
lM}-'8tt?
KO~KaN
'采集窗口参数常量 s^SU6P/]
Public Const FrameH As Long = 280& /H"fycZ
Public Const FrameW As Long = 768& F\^8k /0
Public Const pFrameSize As Long = FrameW * FrameH TnKv)%VF
UP$>,05z6
'标志区范围,用于识别车辆 +/l@o
u'
Public Const PilarC As Integer = 260 '识别标志立柱中线坐标X _hJdC|/
Public Const mkW As Integer = 28 '识别标志立柱宽度 9P)!v.,T/
Public Const mkH As Integer = 80 ''识别标志立柱高度(上白中黑下白) # AC
T&J
Public Const mkY As Integer = 4 ''识别标志立柱Y坐标(40-79白, 80-119黑,120-159白) de)4)EzUP
Public Const mkX As Integer = PilarC - mkW / 2 '识别标志立柱X坐标 *S"RU~1_
'车缝检测位置常数 ?|/K(}
Public Const sSize As Long = 32& x,]x>Up
Public Const sPos As Long = 310& ]z5hTY
Public Const sPosL As Long = 200& 9<&M~(dwT4
Public Const sPosR As Long = 500& (QL:7
'车缝检测框位置 9(OeH7
Public Slice(1 To sSize, 1 To FrameH) As Byte CLk,]kA'r
Public SliceL(1 To sSize, 1 To FrameH) As Byte ~]QQaP
Public SliceR(1 To sSize, 1 To FrameH) As Byte B@NBN&Fr
Public avSL As Integer, avSLR As Integer, avSLL As Integer ~[dL:=?c
"]kzt ux
HfgTc
h
Public MKpilar(1 To mkW * mkH) As Byte '一维数组用于亮度对比度分析,比使用二维数组更便于VB编译优化 KvEv0L<ky
'该数组用于亮度对比度调节、车辆通过识别与车皮间隔识别 8)=(eI$
Public BsLine(1 To 4 * FrameW) As Byte, bsAV As Integer '图像的前4行。用于确定标志区的亮度与对比度范围 ~CbiKez
Public PilarW As Long, PilarH As Long, PilarX As Long, PilarY As Long |59)6/i
Public LeftBK(1 To 1024, 0 To 1) As Byte, RightBK(1 To 1024, 0 To 1) As Byte }Hq3]LVE
'前后帧左右上角128列*8行像素块,根据平均值差绝对值判断进车方向 ep?D;g
*4NY"EwjN
Y]KHCY
0ju-l=w
'一次连续采集的帧数 n|6G\99l+M
Public tFrames As Long [@5cYeW3.
/}
z9(
'在采集卡申请的缓存中,是按帧为单位的,每一帧包含奇偶场两场的数据 8h }a:/
'而该卡的硬件设置是按场采集,只需要读第一场的数据即可。 rab$[?]
'所以要设置的缓存帧的大小是frameW*frameH*2,而一场的数据量为pFrameSize rks"y&&Nc
O39
Public pFRAME(1 To FrameW, 1 To FrameH) As Byte 4w=v
/WDo
Public pBuffer(1 To FrameW * FrameH * 2) As Byte 4x(m.u@
Public pWorkSpace(1 To FrameW * FrameH) As Long 7<*0fy5n n
Public Const pBufferSize As Long = FrameW * FrameH * 2 sve} ent
Public pGray(0 To 255) As Long '整幅图像的灰度直方图 t&EizH$
VFx[{Hy
Public hBoard As Long '采集卡标识 {:*G/*1[.
Public mBufferAddr As Long '缓存地址 f<i
K%
Public BufferSize As Long '缓存大小(字节) CHZ/@g
c
Public iCurrentCard As Long [ 5!}+8]W
Public CapStatus As Long ~
tyqvHC
Public iFrames As Long ygj%VG
Public currentBr As Byte, currentContr As Byte 0%%U7GFB5
+_$s9`@]6
Public hMEM As Long, mStatus As Long :9ia|lN
Public Const hMemSize As Long = pFrameSize * 4 nDO
7
Public hMemWork As Long pe0ax-Zv
Public Const hMemWorkSize As Long = pFrameSize * 5 ]u!s-=3s
0kj5r*qA
:$k1I-^R
sS;)d
'串口接收轨道衡数据 )W>$_QxbN
Public WeightFromCom As String cu
foP&
Public bReceiveComplete As Boolean 1.k=ji$D0
x {Utf$|
wK7w[Xt
Public Type GrayBMPHeader k ,ldi
Tag As Integer ,Yx<"2 W
FileLength As Long '文件大小 cW_wIy\]&
Reserve1 As Long v%AepK&
DataOffset As Long '图像数据偏移量 =X^
a
BMPHeaderSize As Long '文件头长 M>Tg$^lm
'length of the bitmap info header used to describe the bitmap colors, compression,… }2LWDQ;po
'the following sizes are possible: n44 T4q
'28h - windows 3.1x, 95, nt, … !j`<iPI7B
'0ch - os/2 1.x 6H:
fg
'f0h - os/2 2.x >6jal?4u-
V 0Oqq0\
ImageWidth As Long '图像宽(像素数) S|)atJJ0G"
ImageHeight As Long '图像高(像素数) " "m-5PGYo
PlaneNumber As Integer '图像层数 l0`bseN<
bpp As Integer 'bits per pixels '1 - monochrome bitmap e)B1)c 8s
'4 - 16 color bitmap
6E
K <9M
'8 - 256 color bitmap _AX,}9
'16 - 16bit (high color) bitmap &V$cwB
'24 - 24bit (true color) bitmap dm[cl~[
Q
'32 - 32bit (true color) bitmap IqFcrU$4
Compression As Long '压缩方法 '0 - none (also identified by bi_rgb) ~!~i_L\V
'1 - rle 8-bit / pixel (also identified by bi_rle4) MD;Z UAX<
'2 - rle 4-bit / pixel (also identified by bi_rle8) ]xMZo){[|
'3 - bitfields (also identified by bi_bitfields) "{qn
m+G
IMAGESIZE As Long '图像数据字节数 )mf|3/o
hResolution As Long '水平分辩率 像素数/米 ;`LG WT-<F
vResolution As Long '垂直分辩率 \wsVO"/
ColorsinBMP As Long '图中所用的颜色。对256色图像总为0x100 j0~am,yZ
ImportantColors As Long GiX3c^V"1
Pallate(0 To 255) As Long '图像每个值对应的实际显示颜色,项数对应PallateNumber所指调色板项数 %L-qAI&V
End Type F nXm;k,9*
{*F
=&D
L&)e}"
k(^TXUK\o
Public BMPHeader As GrayBMPHeader, BMP1 As GrayBMPHeader YW6a?f^!
Public sRECT As RECT mj e9i
&
[@)Er=
aaCRZKr
Public conn As ADODB.Connection e+-#/i*
Public rsTrain As ADODB.Recordset #}B1W&\sw
Public rsOperater As ADODB.Recordset 8..|-<w
Public rsGoods As ADODB.Recordset IB|6\uKn
Public rsGood2 As ADODB.Recordset <uB)u>3
Public rsSender As ADODB.Recordset X,aRL6>r
Public rsReceover As ADODB.Recordset .O'~s/h
Public rsTrainTMP As ADODB.Recordset gBhX=2%
``k[CgV
No6-i{HZ
'打开采集卡 f~\H|E8(
'设置参数 4)D~S4{E5
'设置为实时单帧采集到缓存方式 poW%F zj
'由另一线程查询采集状态,如果完成采集,传送至用户数组分析或保存 :%J;[bS+
g[1>|Ax`'
;YY<KuT
Sub Main() mY/"rm
Dim i As Integer, status As Long -K?lhu
o*/;Zp==
InitBMPinfo 9ghzK?Yc
'生成BMP文件头---该文件头是固定将pFRAME数组写成BMP文件 Jh=.}FXnjL
BMPHeader.Tag = &H4D42 ,'HjL:r
BMPHeader.ImageWidth = FrameW y3b"'-%
BMPHeader.ImageHeight = FrameH N,rd= m+
BMPHeader.BMPHeaderSize = &H28 *(1<J2j
BMPHeader.PlaneNumber = 1 tmq?h%O>
BMPHeader.bpp = 8 J/K~8sc
BMPHeader.Compression = 0 Q"u2<
BMPHeader.hResolution = &H1274 'Windows pBrush.exe的默认值,PhotoED.exe默值为0 BXU0f%"8U
BMPHeader.vResolution = &H1274 0+op|bdj
BMPHeader.ColorsinBMP = 256 n@ba>m4{
BMPHeader.ImportantColors = BMPHeader.ColorsinBMP Ul/m]b6-
BMPHeader.DataOffset = Len(BMPHeader) "*D9.LyM
For i = 0 To 255 ,LxZbo!
BMPHeader.Pallate(i) = RGB(i, i, i) u8KQV7E
Next i 8g!79q\c4
BMPHeader.IMAGESIZE = FrameH * FrameW CF','gPnc
BMPHeader.FileLength = Len(BMPHeader) + BMPHeader.IMAGESIZE -.?
@f
tY
e,p*R?Y{[
d3q.i5']G
MoveMemory BMP1, BMPHeader, Len(BMPHeader) !`H{jwH
/"st
sF
BMP1.ImageWidth = FrameW PkyX,mr#1
BMP1.ImageHeight = FrameH * 2 +em!TO
BMP1.IMAGESIZE = BMP1.ImageWidth * BMP1.ImageHeight \9OKf|#j
BMP1.FileLength = Len(BMP1) + BMP1.IMAGESIZE \RR`
F .7
)'f=!'X
'确定标志位置,为pilarX, pilarY确定初始值 t !6sU]{
PilarW = mkW R|8L'H+1x
PilarH = mkH '此两项为固定值 EG qu-WBS
PilarX = GetSetting(App.EXEName, "Mark", "MarkX", mkX) As>Og
PilarY = GetSetting(App.EXEName, "Mark", "MarkY", mkY) '此两项需要在程序初始化时检查并进行调整 8CRbo24"s
[zN*P$
U]
Y%
\3 N
'连续采集记录文件 (_ :82@c
' 建立一个缓冲区为页对齐方式的文件 !Whx^B:
If Dir(TmpFile) <> "" Then H!7?#tRU
hFile = CreateFile(TmpFile, GENERIC_READ Or GENERIC_WRITE, _ \
[OB.
0&, 0&, OPEN_ALWAYS, FILE_FLAG_NO_BUFFERING, 0&) %La7);SeY
' 在95/98中,如果打开文件时没有声明overlapped方式,在读定文件时就不能使用overlapped参数项 )@I] Rk?
' 而必须用setfilepointer函数调节与操作系统保留的文件指针。
^`lrKk
Else }JST(d
&
hFile = CreateFile(TmpFile, GENERIC_READ Or GENERIC_WRITE, _ N atC}k
0&, 0&, CREATE_ALWAYS, FILE_FLAG_NO_BUFFERING, 0&) v5\ALWy+p
End If 4(P<'FK $
If hFile = 0 Then 1aS:bFi`
MsgBox TmpFile & ": File Open Error", vbOKOnly ibZ[U p?
Exit Sub n:wAxU
End If WO9vOS>
'采集参数记录文件 OAs>F"
hBCFile = FreeFile() 3bezYk
Open TmpFile + ".BC" For Binary Access Read Write As #hBCFile )8g&lyT
2;>uP#1]
hMEM = VirtualAlloc(ByVal 0&, hMemSize, MEM_COMMIT, PAGE_READWRITE) ’分配系统内容 h%u!UHA
If hMEM = 0 Then zLe(#8G
fStatus = GetLastError B,_K mHItd
MsgBox "内存分配错误: 错误代码 - " & Str(fStatus) & vbCrLf _ 8g)$%Fy+N
& "请向技术人员报告该错误代码。", vbOKOnly w=(dJ(7gu
CloseHandle hFile ;`pIq-=
Exit Sub h_P[B
End If "}1cQ|0a
OqMdm~4B!j
hMemWork = VirtualAlloc(ByVal 0&, hMemWorkSize, MEM_COMMIT, PAGE_READWRITE) Uaux0W
If hMemWork = 0 Then qzvht4
fStatus = GetLastError "#gKI/[qxq
MsgBox "内存分配错误: 错误代码 - " & Str(fStatus) & vbCrLf _ iR9duP+
& "请向技术人员报告该错误代码。", vbOKOnly xg,
9~f[
'释放已成功分配的内存 ;%
KS?;%[
mStatus = VirtualFree(ByVal hMEM, hMemSize, MEM_DECOMMIT) @.a59kP8X
mStatus = VirtualFree(ByVal hMEM, 0&, MEM_RELEASE) mD% qDKI
ZDzG8E0Sq
CloseHandle hFile r vq{Dfo=
Exit Sub >gL&a#<S
End If n_]B5U
./3/3&6
' Test writing PPV T2;9
'WriteFile hFile, ByVal hMEM, ByVal 4096&, bytesRW, ByVal 0& *2-b&PQR{
0iM'),v[]
'初始化采集卡参数
+u
g2p;<B
iCurrentCard = -1 6(7{|iY
hBoard = okOpenBoard(iCurrentCard) HU/4K7e`
Debug.Print hBoard =s*c(>
If hBoard = 0 Then z.RM85 ?T
ExitGrabber {aV,h@>
End wAW{{ p
End If 73S
N\
okGetBufferSize hBoard, mBufferAddr, BufferSize :
%AEwRZ
If mBufferAddr = 0 Then `?[,1
MsgBox "缓存不存在!" >#&2 5,Q
ExitGrabber
Hp ;$fQ
End If J9tV|0
Debug.Print Hex(mBufferAddr), Hex(BufferSize) ~ehN%-
vJi<PQ6
( 1
currentBr = 128: currentContr = 128 4noy!h
'设置视频输入参数 'J0I$-QYk
okSetVideoParam hBoard, VIDEO_SOURCECHAN, 1 'Video2 XPdqE`w=$p
' lParam=0,1.. Comp.Video; 0x100,101...to Y/C(S-Video), 0x200,0x201 to RGB Chan.Input kzK9.
okSetVideoParam hBoard, VIDEO_BRIGHTNESS, currentBr '亮度 x%ccNP0
okSetVideoParam hBoard, VIDEO_CONTRAST, currentContr '对比度 ---初始设置条件下如果图像亮度达不到基本要求则控制灯光 9* 3;v;F
okSetVideoParam hBoard, VIDEO_RGBFORMAT, FORM_GRAY8 '8位灰度模式 0uM&F[.x@g
okSetVideoParam hBoard, VIDEO_TVSTANDARD, 0 'PAL制式 +!ljq~%
okSetVideoParam hBoard, VIDEO_SIGNALTYPE, &H10000 '逐行(低字)同步开槽(高字) cVMRSp
okSetVideoParam hBoard, VIDEO_RECTSHIFT, 144 + &H2C0000 '有效区起始位置:高字Y偏移,低字X偏移 (144/44经验值) nvwf!iU6
okSetVideoParam hBoard, VIDEO_AVAILRECTSIZE, FrameW + FrameH * 2 * &H10000 '有效区大小:低字X高字Y (768/576采集卡最大值) Ylu\]pr9|C
okSetVideoParam hBoard, VIDEO_FREQSEG, 0 ' 低频部分信号 6!itr"
nIL67&
'设置采集参数 B:UM2Jl
okSetCaptureParam hBoard, CAPTURE_INTERVAL, 0 '逐帧 &M3KJ I0L
okSetCaptureParam hBoard, CAPTURE_CLIPMODE, 2 '裁剪方式 3HcduJntl
okSetCaptureParam hBoard, CAPTURE_BUFRGBFORMAT, FORM_GRAY8 '8位灰度 noz1W ]
okSetCaptureParam hBoard, CAPTURE_HARDMIRROR, 0 '不作镜像变换 Yd~J(
okSetCaptureParam hBoard, CAPTURE_FRMRGBFORMAT, FORM_GRAY8 '帧存格式
Q1yXdw
okSetCaptureParam hBoard, CAPTURE_SAMPLEFIELD, 0 ' 逐场采集 | X#!5u
okSetCaptureParam hBoard, CAPTURE_HORZPIXELS, 944 '水平像素数 PAL制式固定值 8b-mW>xsA
okSetCaptureParam hBoard, CAPTURE_VERTLINES, 625 '垂直线数 3'i(wI~<[
okSetCaptureParam hBoard, CAPTURE_SEQCAPWAIT, 0 '不等结束立即返回 @x!+_z
'okSetCaptureParam hBoard, CAPTURE_BUFBLOCKSIZE, FrameW + FrameH * 2 * &H10000 X}x\n\Z
'Buffer Block Size不用设置,而用okSetTargetRect函数进行动态调节 =6 zK1Z
!"RRw&0M
t\YM Hq<Y
okCloseBoard hBoard ;-"q;&1e
Sleep 50 Nr*X1lJ6
hBoard = okOpenBoard(iCurrentCard) '关闭后重新打开使新的设置值生效
tKh
fdwP@6eh
'设置数据传送方式 A1Uy|Dl
'okSetConvertParam hBoard, CONVERT_FIELDEXTEND, FIELD_COPYEXTEND '逐行并扩展行 o+XQMg
'该设置对本程序无意义,因为程序直接用CopyMemory方法读缓存,而扩展行方式是在用采集卡内置函数读RECT过程中实现的。 2)0J@r'
Gl|n }wo$
sRECT.Right = -1 '用于获得当前设置值 :Hr
Fbq
iFrames = okSetTargetRect(hBoard, BUFFER, sRECT) n q>F_h
Debug.Print sRECT.Left, sRECT.Right, sRECT.Top, sRECT.Bottom 2T?Y
Debug.Print okSetCaptureParam(hBoard, CAPTURE_BUFBLOCKSIZE, -1) 'FrameW + FrameH * &H10000 /joY? T
sRECT.Left = 0 ^\`a-l^
sRECT.Top = 0 [Pjitw/?
sRECT.Right = sRECT.Left + FrameW a%kvC#B
sRECT.Bottom = sRECT.Top + FrameH * 2 [.Fq
l+
iFrames = okSetTargetRect(hBoard, BUFFER, sRECT) !J@!2S9
R)SY#*Y
sRECT.Right = -1 '检查新设置值 tq'ri-c&b
iFrames = okSetTargetRect(hBoard, BUFFER, sRECT) q7soV(P
Debug.Print sRECT.Left, sRECT.Right, sRECT.Top, sRECT.Bottom -L6CEe
Debug.Print Hex(okSetCaptureParam(hBoard, CAPTURE_BUFBLOCKSIZE, -1)) biw .
~
BAvz @H
If TESTSignal = False Then eGpKoq7a
'ExitGrabber 88S:E7
$
End If \Z42EnJ
1$C?+H
gE^pOn
HIE8@Rv/3
'设为实时采集状态 ]s
)Y
">6
'iFrames = okCaptureActive(hBoard, BUFFER, 0&) ^LB]
?GhMGpdMq
f2M*]{N
'单帧采集 %*Mr ^=
'okWaitSignalEvent hBoard, EVENT_FRAMEHEADER, -1 Dyo^O=0c
'iFrames = okCaptureSingle(hBoard, BUFFER, 0&) ~G=E
Q]a
okCaptureTo hBoard, BUFFER, 0, 1 'single xz.M'az\
'Do While okGetCaptureStatus(hBoard, False) <> 0 %-K5sIz
' Sleep 20 @K*W3&