I am trying to use the ISampleGrabberCB::BufferCB to convert the current frame to bitmap using the following code:
int ISampleGrabberCB.BufferCB(double sampleTime, IntPtr buffer, int bufferLength)
{
try
{
Form1 form1 = new Form1("", "", "");
if (pictureReady == null)
{
Debug.Assert(bufferLength == Math.Abs(pitch) * videoHeight, "Wrong Buffer Length");
}
Debug.Assert(imageBuffer != IntPtr.Zero, "Remove Buffer");
Bitmap bitmapOfCurrentFrame = new Bitmap(width, height, capturePitch, PixelFormat.Format24bppRgb, buffer);
MessageBox.Show("Works");
form1.changepicturebox3(bitmapOfCurrentFrame);
pictureReady.Set();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
return 0;
}
However this does not seem to be working.
Additionally it seems to call this function when i press a button which runs the following code:
public IntPtr getFrame()
{
int hr;
try
{
pictureReady.Reset();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
imageBuffer = Marshal.AllocCoTaskMem(Math.Abs(pitch) * videoHeight);
try
{
gotFrame = true;
if (videoControl != null)
{
hr = videoControl.SetMode(stillPin, VideoControlFlags.Trigger);
DsError.ThrowExceptionForHR(hr);
}
if (!pictureReady.WaitOne(9000, false))
{
throw new Exception("Timeout waiting to get picture");
}
}
catch
{
Marshal.FreeCoTaskMem(imageBuffer);
imageBuffer = IntPtr.Zero;
}
return imageBuffer;
}
Once this code is ran I get a message box which shows 'Works' thus meaning my BufferCB must of been called however does not update my picture box with the current image.
Is the BufferCB not called after every new frame? If so why do I not recieve the 'Works' message box?
Finally is it possible to convert every new frame into a bitmap (this is used for later processing) using BufferCB and if so how?
Edited code:
int ISampleGrabberCB.BufferCB(double sampleTime, IntPtr buffer, int bufferLength)
{
Debug.Assert(bufferLength == Math.Abs(pitch) * videoHeight, "Wrong Buffer Length");
Debug.Assert(imageBuffer != IntPtr.Zero, "Remove Buffer");
CopyMemory(imageBuffer, buffer, bufferLength);
Decode(buffer);
return 0;
}
public Image Decode(IntPtr imageData)
{
var bitmap = new Bitmap(width, height, pitch, PixelFormat.Format24bppRgb, imageBuffer);
bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);
Form1 form1 = new Form1("", "", "");
form1.changepicturebox3(bitmap);
bitmap.Save("C:\\Users\\...\\Desktop\\A2 Project\\barcode.jpg");
return bitmap;
}
Button code:
public void getFrameFromWebcam()
{
if (iPtr != IntPtr.Zero)
{
Marshal.FreeCoTaskMem(iPtr);
iPtr = IntPtr.Zero;
}
//Get Image
iPtr = sampleGrabberCallBack.getFrame();
Bitmap bitmapOfFrame = new Bitmap(sampleGrabberCallBack.width, sampleGrabberCallBack.height, sampleGrabberCallBack.capturePitch, PixelFormat.Format24bppRgb, iPtr);
bitmapOfFrame.RotateFlip(RotateFlipType.RotateNoneFlipY);
barcodeReader(bitmapOfFrame);
}
public IntPtr getFrame()
{
int hr;
try
{
pictureReady.Reset();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
imageBuffer = Marshal.AllocCoTaskMem(Math.Abs(pitch) * videoHeight);
try
{
gotFrame = true;
if (videoControl != null)
{
hr = videoControl.SetMode(stillPin, VideoControlFlags.Trigger);
DsError.ThrowExceptionForHR(hr);
}
if (!pictureReady.WaitOne(9000, false))
{
throw new Exception("Timeout waiting to get picture");
}
}
catch
{
Marshal.FreeCoTaskMem(imageBuffer);
imageBuffer = IntPtr.Zero;
}
return imageBuffer;
}
I also still need to press the button to run the BufferCB
Thanks for reading.
BufferCB is called for every new frame that has been captured by the camera. You don't see the message box, because the method is called from another thread (not the ui thread). See this question for details.
In my code I used AutoResetEvent for capturing a frame:
#region samplegrabber
/// <summary>
/// buffer callback, COULD BE FROM FOREIGN THREAD.
/// </summary>
int ISampleGrabberCB.BufferCB (double sampleTime,
IntPtr pBuffer,
int bufferLen)
{
if (_sampleRequest)
{
_sampleRequest = false;
if (bufferLen > _bufferSize)
throw new Exception ("buffer is wrong size");
Win32.CopyMemory (_buffer, pBuffer, _bufferSize);
// Picture is ready.
_resetEvent.Set ();
}
else
_dropped++;
return 0;
}
The image can then be decoded from the IntPtr with another function:
public Image Decode (IntPtr data)
{
var bitmap = new Bitmap (_width, _height, _stride, PixelFormat.Format24bppRgb, data);
bitmap.RotateFlip (RotateFlipType.RotateNoneFlipY);
return bitmap;
}
Related
i have a project that captures images by basler camera and for this i have a onimagegrabbed Function that grabs image.
while running my project in any cpu it i did not getting any error. but when i turned to x86 , project runs but after 2 or 3 seconds I am getting exception message " system.argumentexception parameter is not valid. at system.drawing.bitmap..ctor(int32 width, int32 height, pixelformat format) ."
also gettig this message in this in console tab
"Exception thrown: 'System.ArgumentException' in System.Drawing.dll"
the exception message screenshot is here
heres what i have tried
private void OnImageGrabbed(object sender, ImageGrabbedEventArgs e)
{
bool invokeRequired = base.InvokeRequired;
if (invokeRequired)
{
base.BeginInvoke(new EventHandler<ImageGrabbedEventArgs>(this.OnImageGrabbed), new object[]
{
sender,
e.Clone()
});
}
else
{
try
{
this.grabResult = e.GrabResult;
bool isValid = this.grabResult.IsValid;
if (isValid)
{
bool flag = !this.stopWatch.IsRunning || this.stopWatch.ElapsedMilliseconds > 33L;
if (flag)
{
this.stopWatch.Restart();
Bitmap bitmap = new Bitmap(this.grabResult.Width, this.grabResult.Height, PixelFormat.Format32bppRgb);
BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
this.converter.OutputPixelFormat = PixelType.BGRA8packed;
IntPtr scan = bitmapData.Scan0;
this.converter.Convert(scan, (long)(bitmapData.Stride * bitmap.Height), this.grabResult);
bitmap.UnlockBits(bitmapData);
object obj = this.lockObject;
lock (obj)
{
Bitmap bitmap2 = this.DisplayWindow.Image as Bitmap;
bitmap.RotateFlip(RotateFlipType.Rotate90FlipNone);
this.gb = this.CreateNonIndexedImage(bitmap);
this.DisplayWindow.Image = bitmap;
bool flag3 = bitmap2 != null;
if (flag3)
{
bitmap2.Dispose();
}
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
finally
{
e.DisposeGrabResultIfClone();
}
}
}
the line:150 is " Bitmap bitmap = new Bitmap(this.grabResult.Width, this.grabResult.Height, PixelFormat.Format32bppRgb);"
I am getting error "A generic error occurred in GDI+".
I have code below, but it error after some time while loop. I research for all and can not fix it, please help me
public Color GetColorAt(int x, int y)
{
x = x - rect.Left - 7;
y = y - rect.Top - 31;
Color c = Color.Black;
IntPtr hDC = PlatformInvokeUSER32.GetDC(proc.MainWindowHandle);
try
{
if (hDC != IntPtr.Zero)
{
IntPtr hMemDC = PlatformInvokeGDI32.CreateCompatibleDC(hDC);
if (hMemDC != IntPtr.Zero)
{
IntPtr m_HBitmap = PlatformInvokeGDI32.CreateCompatibleBitmap(hDC, 1, 1);
if (m_HBitmap != IntPtr.Zero)
{
IntPtr hOld = (IntPtr)PlatformInvokeGDI32.SelectObject(hMemDC, m_HBitmap);
PlatformInvokeGDI32.BitBlt(hMemDC, 0, 0, 1, 1, hDC, x, y, PlatformInvokeGDI32.SRCCOPY);
PlatformInvokeGDI32.SelectObject(hMemDC, hOld);
Bitmap screen = Image.FromHbitmap(m_HBitmap);
c = screen.GetPixel(0, 0);
screen.Dispose();
}
PlatformInvokeGDI32.DeleteObject(m_HBitmap);
PlatformInvokeGDI32.DeleteDC(m_HBitmap);
}
PlatformInvokeGDI32.DeleteDC(hMemDC);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.StackTrace);
}
PlatformInvokeUSER32.ReleaseDC(proc.MainWindowHandle, hDC);
PlatformInvokeGDI32.DeleteDC(hDC);
GC.Collect();
return c;
}
Using call function while loop realtime
public Form1()
{
InitializeComponent();
while (true)
{
Color c = GetColorAt(50, 50);
Thread.Sleep(10);
}
}
I make screenshot of a window in a infinite loop
it works good.
But I hope it can be improved.
When i run my project, it has a litter delay to copy "Myscreen" from "PictureBox".
Anyone have a idea?
Or did you know any other solutions?
I just want to get Screen's BITMAP constantly.(faster..)
Below source is screen capture function.
public static Bitmap ScreenCapture_B(System.Windows.Forms.Screen MyScreen)
{
try
{
Rectangle rect = MyScreen.Bounds;
// 2nd screen = Screen.AllScreens[1]
int bitsPerPixel = MyScreen.BitsPerPixel;
PixelFormat pixelFormat = PixelFormat.Format32bppArgb;
if (bitsPerPixel <= 16)
{
pixelFormat = PixelFormat.Format16bppRgb565;
}
if (bitsPerPixel == 24)
{
pixelFormat = PixelFormat.Format24bppRgb;
}
else
{
pixelFormat = PixelFormat.Format24bppRgb;
}
Bitmap bmp = new Bitmap(rect.Width, rect.Height, pixelFormat);
using (Graphics gr = Graphics.FromImage(bmp))
{
// 화면을 그대로 카피해서 Bitmap 메모리에 저장
gr.CopyFromScreen(rect.Left, rect.Top, 0, 0, rect.Size);
}
return bmp;
}
catch(Exception)
{
throw;
}
}
Bellow source is Thread.
public void ThreadLoop()
{
try
{
//infinite loop
while (true)
{
bm = null;
Screen MyScreen = Screen.PrimaryScreen;
bm = ScreenCapture_B(MyScreen);
setImage(bm, pictureEdit1);
Bitmap btimage = new Bitmap(pictureEdit1.Image);
ProcessImage_new(btimage);
}
}
catch (Exception ex)
{
throw;
}
}
I have a problem, and i don't know how resolved.. I'm using the drive twain to do scanner some documents, and i don't get create a new BitMap when i'm scanning a big number of the files.. So.. i need help to solution this.. my code is:
public static Bitmap FromHDib(IntPtr dibPtrArg, out ServiceError error)
{
error = null;
try
{
Win32.BITMAPINFOHEADER bmi;
IntPtr pixptr;
var ptr = Win32.GlobalLock(dibPtrArg);
GetPixelInfo(ptr, out pixptr, out bmi);
Bitmap bitMap = new Bitmap(bmi.biWidth, bmi.biHeight);
Graphics scannedImageGraphics = Graphics.FromImage(bitMap);
**IntPtr hdc = scannedImageGraphics.GetHdc();** //parameter is not valid
SetDIBitsToDevice(
hdc,
0, // XDest
0, // YDest
bmi.biWidth,
bmi.biHeight,
0, // XSrc
0, // YSrc
0, // uStartScan
bmi.biHeight, // cScanLines
pixptr, // lpvBits
ptr, // lpbmi
0); // 0 = literal RGB values rather than palette
scannedImageGraphics.ReleaseHdc(hdc);
const float inchPerMeter = 39.3700787F;
bitMap.SetResolution(bmi.biXPelsPerMeter / inchPerMeter, bmi.biYPelsPerMeter / inchPerMeter);
Win32.GlobalUnlock(dibPtrArg);
Win32.GlobalFree(dibPtrArg);
Win32.DeleteDC(hdc);
bitMap.Dispose();
return bitMap;
}
catch (OutOfMemoryException memoryEx)
{
return new Bitmap(0, 0);
}
catch (ArgumentException argEx)
{
return new Bitmap(0, 0);
}
}
I need help with HikVision IPCam Video streaming. I searched for 2 hole weeks without luck.
My problem is the IPCamm DLL stream the image into a picturebox using PictureBox.Handle. Its working perfectly fine:
[DllImport("HCNetSDK.dll")]
public static extern int NET_DVR_RealPlay_V30(int lUserID, ref NET_DVR_CLIENTINFO lpClientInfo, RealDataCallBack_V30 fRealDataCallBack_V30, IntPtr pUser, bool bBlocked);
this.realDataCallBack = new RealDataCallBack_V30(RealDataCallback);
this.clientInfo.hPlayWnd = PictureBox.Handle;
this.clientInfo.lChannel = channel;
this.clientInfo.lLinkMode = 0;
this.playHandle = NET_DVR_RealPlay_V30(this.userID, ref this.clientInfo, realDataCallBack, IntPtr.Zero, true);
My Issue is that I need to process the image but I couldn't have any way to capture the image as Bitmap or Image and then display it As I like.
I tried Bitmap.FromHbitmap(PictureBox.Handle), Tried some MemoryMarshel solutions with no luck.
My Only way to get it now is by getting the data from call back functions which is with lower quality, lower frame-count, ...
This snippet draws the data from the handle into a bitmap and then sets the image of the picturebox. The CopyFromScreen line might not be necessary on older systems.
PictureBox.Image = CaptureControl(PictureBox.Handle, PictureBox.Width, PictureBox.Height);
// PictureBox.Image now contains the data that was drawn to it
[DllImport("gdi32.dll")]
private static extern bool BitBlt(IntPtr hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, int dwRop);
public Bitmap CaptureControl(IntPtr handle, int width, int height)
{
Bitmap controlBmp;
using (Graphics g1 = Graphics.FromHwnd(handle))
{
controlBmp = new Bitmap(width, height, g1);
using (Graphics g2 = Graphics.FromImage(controlBmp))
{
g2.CopyFromScreen(this.Location.X + PictureBox.Left, this.Location.Y + PictureBox.Top, 0, 0, PictureBox.Size);
IntPtr dc1 = g1.GetHdc();
IntPtr dc2 = g2.GetHdc();
BitBlt(dc2, 0, 0, width, height, handle, 0, 0, 13369376);
g1.ReleaseHdc(dc1);
g2.ReleaseHdc(dc2);
}
}
return controlBmp;
}
You need to set hPlayWnd as zero. Set callback function to work on decoded data. I try to understand Hikvision SDK, a few difficult...
lpPreviewInfo.hPlayWnd = IntPtr.Zero;//预览窗口 live view window
m_ptrRealHandle = RealPlayWnd.Handle;
RealData = new CHCNetSDK.REALDATACALLBACK(RealDataCallBack);//预览实时流回调函数 real-time stream callback function
m_lRealHandle = CHCNetSDK.NET_DVR_RealPlay_V40(m_lUserID, ref lpPreviewInfo, RealData, pUser);
public void RealDataCallBack(Int32 lRealHandle, UInt32 dwDataType, IntPtr pBuffer, UInt32 dwBufSize, IntPtr pUser)
//解码回调函数
private void DecCallbackFUN(int nPort, IntPtr pBuf, int nSize, ref PlayCtrl.FRAME_INFO pFrameInfo, int nReserved1, int nReserved2)
{
// 将pBuf解码后视频输入写入文件中(解码后YUV数据量极大,尤其是高清码流,不建议在回调函数中处理)
if (pFrameInfo.nType == 3) //#define T_YV12 3
{
// FileStream fs = null;
// BinaryWriter bw = null;
// try
// {
// fs = new FileStream("DecodedVideo.yuv", FileMode.Append);
// bw = new BinaryWriter(fs);
// byte[] byteBuf = new byte[nSize];
// Marshal.Copy(pBuf, byteBuf, 0, nSize);
// bw.Write(byteBuf);
// bw.Flush();
// }
// catch (System.Exception ex)
// {
// MessageBox.Show(ex.ToString());
// }
// finally
// {
// bw.Close();
// fs.Close();
// }
}
}
See the source code