各位大侠,我编了个图像采集的程序,图像卡用的是大恒CG300。图像采集后进行了二值处理。画面闪烁不停,而且运行4到5分钟后,就出来了一个错误提示框:Project Project1.exe raised exception class EOutOfResources with message 'Out of system resource' .Process stopped or Run to continue.这个问题已经困扰我三天了,还是找不到原因,我觉得我把资源都及时释放了啊。请各位大侠前辈抽空帮我看看到底问题出在哪里,非常谢谢您了!!!btw:特别想请大家帮我看看function TForm1.Draw这个函数,我觉得这里出问题的可能性较大。程序如下:(由于论坛里不能贴太长的贴子,所以前面的接口声明部分及一些变量声明我就没贴出来了)
  //用户创建的一帧图像数据缓冲区大小,用来将图像卡采集到内存的数据读出到该缓冲区
  ImgBufLength: LongWord;
  //图像卡采集的每帧数据数据大小
  BufLength: LongWord;  pBMIInfo: PBITMAPINFO;
  pBuffer: PChar;
  Bmp: TBitmap;const
  INPUT_WINDOW_X = 0;
  INPUT_WINDOW_Y = 0;
  INPUT_WINDOW_WIDTH = 400;
  INPUT_WINDOW_HEIGHT = 300;  OUTPUT_WINDOW_X = 0;
  OUTPUT_WINDOW_Y = 0;
  OUTPUT_WINDOW_WIDTH = 400;
  OUTPUT_WINDOW_HEIGHT = 300;
  procedure TForm1.FormCreate(Sender: TObject);
begin
  //颜色空间类型,RGB565
  ColorSpace := RGB565;  //各种图像卡参数设置,用户可更改
  VideoStandard := PAL;  //采集模式帧方式
  DispMode := FRAME;  //源路为复合视频一
  Source.nType := COMPOSITE_VIDEO;
  Source.nIndex := 0;  //晶振为35M
  CryOsc := CRY_OSC_35M;  //亮度128
  byBrightness := 128;  //对比度128
  byContrast := 128;  //色调128
  byHue := 128;  //饱和度128
  bySaturation := 128;
  if (BeginCGCard(1, hCGCard) = CG_OK) then
  begin
    bInit := True;    //颜色空间类型,按照当前Windows显示属性设置
    CG_VERIFY(CGSetVideoFormat(hCGCard, ColorSpace));
    //采集模式,帧方式
    CG_VERIFY(CGSetScanMode(hCGCard, DispMode));
    //源路,默认是第一路
    CG_VERIFY(CGSetVideoSource(hCGCard, Source));
    //晶振, 默认为35M
    CG_VERIFY(CGSelectCryOsc(hCGCard, CryOsc));
    //亮度,默认是128
    CG_VERIFY(CGAdjustVideo(hCGCard, BRIGHTNESS, byBrightness));
    //对比度,默认是128
    CG_VERIFY(CGAdjustVideo(hCGCard, CONTRAST, byContrast));
    //色调,默认是128
    CG_VERIFY(CGAdjustVideo(hCGCard, HUE, byHue));
    //包含度,默认是128
    CG_VERIFY(CGAdjustVideo(hCGCard, SATURATION, bySaturation));
    //设置输入视频窗口大小
    CG_VERIFY(CGSetInputWindow(hCGCard, INPUT_WINDOW_X,
                                        INPUT_WINDOW_Y,
                                        INPUT_WINDOW_WIDTH,
                                        INPUT_WINDOW_HEIGHT));
    //设置输出图像大小
    CG_VERIFY(CGSetOutputWindow(hCGCard, OUTPUT_WINDOW_X,
                                        OUTPUT_WINDOW_Y,
                                        OUTPUT_WINDOW_WIDTH,
                                        OUTPUT_WINDOW_HEIGHT));
  end
  else
  begin
    MessageBox(0, 'CGCard Init Failed!', 'Warning', MB_OK or MB_ICONWARNING);
  end;
end;
function SnapExCallback(var info: SNAP_INFO): Integer; stdcall
begin    Form1.Draw(info.nNumber);
    result := 1;
end;
function TForm1.Draw (nNumber: Integer): boolean;
var
  MemHandle: LongWord;
  LineAddr: PChar;
  //Bmp: TBitmap;
  VideoDc: HDC;
  p: PByteArray;
  Gray, x, y: Integer;
begin
  VideoDc := GetDc(VideoPanel.Handle);
  //已经固定用GRB565来采集数据了,每帧图像768*576,所以图像卡需要的帧缓冲区大小是
  BufLength := OUTPUT_WINDOW_WIDTH * OUTPUT_WINDOW_HEIGHT * 2;  //用户要不断将采集到静态内存的帧图像数据读出,需要读出后的帧图像数据是24位彩色
  //所以用户自行创建的缓冲区大小是
  ImgBufLength := OUTPUT_WINDOW_WIDTH * OUTPUT_WINDOW_HEIGHT * 3;
  pBuffer := AllocMem(ImgBufLength);
  pBMIInfo := AllocMem(sizeof(TBITMAPINFO)+ (255 * sizeof(TRGBQuad)));
  Bmp := TBitmap.Create;
  //锁定全部保留静态内存给图像卡使用
  CG_VERIFY(CGStaticMemLock(Longword(nNumber) * BufLength, BufLength, MemHandle, LineAddr));
  SetStretchBltMode(VideoDC, COLORONCOLOR);
  Bmp.Width:= OUTPUT_WINDOW_WIDTH;
  Bmp.Height := OUTPUT_WINDOW_HEIGHT;
  Bmp.PixelFormat := pf24bit;
   //设定BMP的头信息
  pBMIInfo^.bmiHeader.biSize := sizeof(BITMAPINFOHEADER);
  pBMIInfo^.bmiHeader.biWidth := OUTPUT_WINDOW_WIDTH;
  pBMIInfo^.bmiHeader.biHeight := OUTPUT_WINDOW_HEIGHT;
  pBMIInfo^.bmiHeader.biPlanes := 1;
  pBMIInfo^.bmiHeader.biBitCount := 24;
  pBMIInfo^.bmiHeader.biCompression := BI_RGB;
  pBMIInfo^.bmiHeader.biSizeImage := 0;
  pBMIInfo^.bmiHeader.biXPelsPerMeter := 0;
  pBMIInfo^.bmiHeader.biYPelsPerMeter := 0;
  pBMIInfo^.bmiHeader.biClrUsed := 0;
  pBMIInfo^.bmiHeader.biClrImportant := 0;
  //读出数据
  CGDataTransform(pBuffer , LineAddr , OUTPUT_WINDOW_WIDTH, OUTPUT_WINDOW_HEIGHT, 16, True);
  SetStretchBltMode(Bmp.Canvas.Handle, COLORONCOLOR);
  SetDIBitsToDevice(Bmp.Canvas.Handle, 0, 0, Bmp.Width, Bmp.Height,
                  0, 0, 0, pBMIInfo^.bmiHeader.biHeight,
                  pBuffer, pBMIInfo^, DIB_RGB_COLORS);
  randomize;
  for y := 0 to Bmp.Height - 1 do
  begin
    p := Bmp.scanline[y];
    for x := 0 to Bmp.Width - 1 do
    begin
      //一个象素点三个字节
      Gray := Round(p[x * 3 + 2] * 0.3 + p[x * 3 + 1] * 0.59 + p[x
                * 3] * 0.11);
      if gray > 128 then //全局阀值128
      begin
        p[x * 3] := 255;
        p[x * 3 + 1] := 255;
        p[x * 3 + 2] := 255;
      end
      else
      begin
        p[x * 3] := 0;
       p[x * 3 + 1] := 0;
        p[x * 3 + 2] := 0;
      end;
    end;
  end;
  //StretchDIBits(VideoDC, 0, 0, VideoPanel.Width, VideoPanel.Height,
   //             0, 0, pBMIInfo^.bmiHeader.biWidth, pBMIInfo^.bmiHeader.biHeight,
    //             pBuffer, pBMIInfo^, DIB_RGB_COLORS, SRCCOPY);
  Image1.Picture.Bitmap.Assign(Bmp);  //用这种方法的显示画面闪烁,而用StretchDIBits不会闪
  Bmp.Free;
  CG_VERIFY(CGStaticMemUnlock(MemHandle));
  ReleaseDC(VideoPanel.Handle, VideoDC);
  result := true;
end;
procedure TForm1.StartSnapButtonClick(Sender: TObject);
var
  status: CGSTATUS;
begin
  if not bInit then Exit;
  status := CGOpenSnapEx(hCGCard, @SnapExCallback, nil);
  if (CG_SUCCESS(status)) then
  begin
    //开始启动Snap连续采集到内存,使用缓存区数是2,即双缓冲采集
    status := CGStartSnapEx(hCGCard, 0, True, 2);
    if ( not CG_SUCCESS(status)) then
        CGCloseSnapEx(hCGCard)
    else
    begin
        //更改按钮状态
        StopSnapButton.Enabled := True;
        StartSnapButton.Enabled := False;
        //切换bSanp状态
        bSnap := True;
    end;
  end;
end;procedure TForm1.StopSnapButtonClick(Sender: TObject);
var
  status: CGSTATUS;
begin
  status := CGCloseSnapEx(hCGCard);
  if (CG_SUCCESS(status)) then
  begin
    bSnap := False;
    //更改按钮状态
    StopSnapButton.Enabled := False;
    StartSnapButton.Enabled := True;
  end;
end;procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  if bSnap then
  begin
    Action := caNone;
    MessageBox(0, 'Can''t Exit! Please Stop Snap Operation!', 'Warning', MB_OK or MB_ICONWARNING);
  end
  else
  begin
    Action := caFree;
  end;
end;procedure TForm1.FormDestroy(Sender: TObject);
begin
  //没有打开卡就没有必要关闭了,直接退出
  if not bInit then
    exit;  if (pBMIInfo <> nil) then
    FreeMem(pBMIInfo, sizeof(TBITMAPINFO)+ (255 * sizeof(TRGBQuad)));
  if (pBuffer <> nil) then
    FreeMem(pBuffer, BufLength);  //关闭采集卡
  CG_VERIFY(EndCGCard(hCGCard));
end;
end.

解决方案 »

  1.   

    谢谢chenchangfu(小虾) ,能给点更具体点的建议吗:)我觉得我的资源都及时释放了啊,我觉得问题可能出在这个函数上,您以及其他各位大侠能帮我看看吗:)function TForm1.Draw (nNumber: Integer): boolean;
    var
      MemHandle: LongWord;
      LineAddr: PChar;
      //Bmp: TBitmap;
      VideoDc: HDC;
      p: PByteArray;
      Gray, x, y: Integer;
    begin
      VideoDc := GetDc(VideoPanel.Handle);
      //已经固定用GRB565来采集数据了,每帧图像768*576,所以图像卡需要的帧缓冲区大小是
      BufLength := OUTPUT_WINDOW_WIDTH * OUTPUT_WINDOW_HEIGHT * 2;  //用户要不断将采集到静态内存的帧图像数据读出,需要读出后的帧图像数据是24位彩色
      //所以用户自行创建的缓冲区大小是
      ImgBufLength := OUTPUT_WINDOW_WIDTH * OUTPUT_WINDOW_HEIGHT * 3;
      pBuffer := AllocMem(ImgBufLength);
      pBMIInfo := AllocMem(sizeof(TBITMAPINFO)+ (255 * sizeof(TRGBQuad)));
      Bmp := TBitmap.Create;
      //锁定全部保留静态内存给图像卡使用
      CG_VERIFY(CGStaticMemLock(Longword(nNumber) * BufLength, BufLength, MemHandle,    
                LineAddr));
      SetStretchBltMode(VideoDC, COLORONCOLOR);
      Bmp.Width:= OUTPUT_WINDOW_WIDTH;
      Bmp.Height := OUTPUT_WINDOW_HEIGHT;
      Bmp.PixelFormat := pf24bit;
       //设定BMP的头信息
      pBMIInfo^.bmiHeader.biSize := sizeof(BITMAPINFOHEADER);
      pBMIInfo^.bmiHeader.biWidth := OUTPUT_WINDOW_WIDTH;
      pBMIInfo^.bmiHeader.biHeight := OUTPUT_WINDOW_HEIGHT;
      pBMIInfo^.bmiHeader.biPlanes := 1;
      pBMIInfo^.bmiHeader.biBitCount := 24;
      pBMIInfo^.bmiHeader.biCompression := BI_RGB;
      pBMIInfo^.bmiHeader.biSizeImage := 0;
      pBMIInfo^.bmiHeader.biXPelsPerMeter := 0;
      pBMIInfo^.bmiHeader.biYPelsPerMeter := 0;
      pBMIInfo^.bmiHeader.biClrUsed := 0;
      pBMIInfo^.bmiHeader.biClrImportant := 0;
      //读出数据
      CGDataTransform(pBuffer , LineAddr , OUTPUT_WINDOW_WIDTH, OUTPUT_WINDOW_HEIGHT, 16, True);
      SetStretchBltMode(Bmp.Canvas.Handle, COLORONCOLOR);
      SetDIBitsToDevice(Bmp.Canvas.Handle, 0, 0, Bmp.Width, Bmp.Height,
                      0, 0, 0, pBMIInfo^.bmiHeader.biHeight,
                      pBuffer, pBMIInfo^, DIB_RGB_COLORS);
      randomize;
      for y := 0 to Bmp.Height - 1 do
      begin
        p := Bmp.scanline[y];
        for x := 0 to Bmp.Width - 1 do
        begin
          //一个象素点三个字节
          Gray := Round(p[x * 3 + 2] * 0.3 + p[x * 3 + 1] * 0.59 + p[x
                    * 3] * 0.11);
          if gray > 128 then //全局阀值128
          begin
            p[x * 3] := 255;
            p[x * 3 + 1] := 255;
            p[x * 3 + 2] := 255;
          end
          else
          begin
            p[x * 3] := 0;
           p[x * 3 + 1] := 0;
            p[x * 3 + 2] := 0;
          end;
        end;
      end;
      Image1.Picture.Bitmap.Assign(Bmp);  //用这种方法的显示画面闪烁,而用StretchDIBits不会闪
      Bmp.Free;
      CG_VERIFY(CGStaticMemUnlock(MemHandle));
      ReleaseDC(VideoPanel.Handle, VideoDC);
      result := true;
    end;
      

  2.   

    1.Image1.Picture.Bitmap.Assign(Bmp); 的上面加一句
      Image1.Picture.Bitmap.freeimage;
    2.加上try...except脱离delphi环境找一下出错的大范围。
      

  3.   

    谢谢 zwm09() 
    我加上Image1.Picture.Bitmap.freeimage;这句后,运行4到5分钟后,还是弹出那个出错对话框,另外还弹出个中文对话框,说虚拟内存太低
      

  4.   

    任务管理器 ->查看- >选择列 : 勾上 “GDI 对象”运行程序,观察"GDI 对象"创建的数目;如果是这个问题,然后按F8步进,看谁创建了没释放完毕。
      

  5.   

    To: S.F. 和potlee
    我按你们说的方法试了下,在运行后,该程序所占用内存不断攀升,在一分钟左右时达到峰值153200K左右,接着就下降并稳定在20000K左右,GDI对象一直在56到61之间。运行到四分钟左右时,程序死了。我电脑配置是256M内存,程序运行时系统可用内存一直在2500到4100之间变动。
    请问我这个程序是内存泄漏的问题还是另有元凶?谢谢大家了!
      

  6.   

    看是不是这两个东东的原因?
    我怎么就没有看到释放呢?
      pBuffer := AllocMem(ImgBufLength);
      pBMIInfo := AllocMem(sizeof(TBITMAPINFO)+ (255 * sizeof(TRGBQuad)));
      

  7.   

    To: duanhai
    那两个东东的释放在顶楼贴子最后面的那个procedure中,即:procedure TForm1.FormDestroy(Sender: TObject);
    begin
      //没有打开卡就没有必要关闭了,直接退出
      if not bInit then
        exit;  if (pBMIInfo <> nil) then
        FreeMem(pBMIInfo, sizeof(TBITMAPINFO)+ (255 * sizeof(TRGBQuad)));
      if (pBuffer <> nil) then
        FreeMem(pBuffer, BufLength);  //关闭采集卡
      CG_VERIFY(EndCGCard(hCGCard));
    end;