I had to change to directshow for my eyetracking software due to the difficulties to change resolution of the camera when using c++ and opencv.
Directshow is new to me and it is kind of hard to understand everything. But I found this nice example that works perfectly for capturing & viewing the web cam.
http://www.codeproject.com/Articles/12869/Real-time-video-image-processing-frame-grabber-usi
I am using the version that not requires directShow SDK. (But it is still directshow that is used in the example, right??)
#include <windows.h>
#include <dshow.h>
#pragma comment(lib,"Strmiids.lib")
#define DsHook(a,b,c) if (!c##_) { INT_PTR* p=b+*(INT_PTR**)a; VirtualProtect(&c##_,4,PAGE_EXECUTE_READWRITE,&no);\
*(INT_PTR*)&c##_=*p; VirtualProtect(p, 4,PAGE_EXECUTE_READWRITE,&no); *p=(INT_PTR)c; }
// Here you get image video data in buf / len. Process it before calling Receive_ because renderer dealocates it.
HRESULT ( __stdcall * Receive_ ) ( void* inst, IMediaSample *smp ) ;
HRESULT __stdcall Receive ( void* inst, IMediaSample *smp ) {
BYTE* buf; smp->GetPointer(&buf); DWORD len = smp->GetActualDataLength();
HRESULT ret = Receive_ ( inst, smp );
return ret;
}
int WINAPI WinMain(HINSTANCE inst,HINSTANCE prev,LPSTR cmd,int show){
HRESULT hr = CoInitialize(0); MSG msg={0}; DWORD no;
IGraphBuilder* graph= 0; hr = CoCreateInstance( CLSID_FilterGraph, 0, CLSCTX_INPROC,IID_IGraphBuilder, (void **)&graph );
IMediaControl* ctrl = 0; hr = graph->QueryInterface( IID_IMediaControl, (void **)&ctrl );
ICreateDevEnum* devs = 0; hr = CoCreateInstance (CLSID_SystemDeviceEnum, 0, CLSCTX_INPROC, IID_ICreateDevEnum, (void **) &devs);
IEnumMoniker* cams = 0; hr = devs?devs->CreateClassEnumerator (CLSID_VideoInputDeviceCategory, &cams, 0):0;
IMoniker* mon = 0; hr = cams->Next (1,&mon,0); // get first found capture device (webcam?)
IBaseFilter* cam = 0; hr = mon->BindToObject(0,0,IID_IBaseFilter, (void**)&cam);
hr = graph->AddFilter(cam, L"Capture Source"); // add web cam to graph as source
IEnumPins* pins = 0; hr = cam?cam->EnumPins(&pins):0; // we need output pin to autogenerate rest of the graph
IPin* pin = 0; hr = pins?pins->Next(1,&pin, 0):0; // via graph->Render
hr = graph->Render(pin); // graph builder now builds whole filter chain including MJPG decompression on some webcams
IEnumFilters* fil = 0; hr = graph->EnumFilters(&fil); // from all newly added filters
IBaseFilter* rnd = 0; hr = fil->Next(1,&rnd,0); // we find last one (renderer)
hr = rnd->EnumPins(&pins); // because data we are intersted in are pumped to renderers input pin
hr = pins->Next(1,&pin, 0); // via Receive member of IMemInputPin interface
IMemInputPin* mem = 0; hr = pin->QueryInterface(IID_IMemInputPin,(void**)&mem);
DsHook(mem,6,Receive); // so we redirect it to our own proc to grab image data
hr = ctrl->Run();
while ( GetMessage( &msg, 0, 0, 0 ) ) {
TranslateMessage( &msg );
DispatchMessage( &msg );
}
};
The method HRESULT Receive is called for every new frame from the cam. the the comments says that buf contains the data. But I have 3 problems/questions.
I cant include the opencv lib. I create a new project in visual studio, and add the same property sheets as I always include. the only difference from earlier projects is that I Now create a totaly empty project, earlier I created a win32 application.
How to add opencv into the directshow project?
The example above. from buf. which is a pointer to the data. How do I get that into iplImage/Mat for the opencv calc?
Is there a way to not show the images from the webcam (I only need to perform some algorithms on the frames, I guess removing the window with the results might give me more power for the analyse algorithms?!)
Thanks!
With DirectShow you typically create a pipeline, that is a graph and you add filters to it, like this:
Camera -> [possibly some extra stuff] -> Sample Grabber -> Null Renderer
Camera, Sample Grabber, Null Renderer are all standard components shipped with clean Windows. Sample Grabber can be set to call you back via ISampleGrabberCB::SampleCB and give you data for every video frame captured. Null Renderer is the termination of pipeline without displaying video on monitor (just video capture).
SampleCB is the keyword to bring you sample code you need. Having data received with this call, you can convert/wrap it into IPL/OpenCV class as suggested by #praks411.
Having it done as simple as this, you don't need DirectShow BaseClasses, and the code will be merely regular ATL/MFC code and project. Make sure to use CComPtr wrapper class to deal with COM interfaces to not lose references and leak objects. Some declarations might be missing in very latest Windows SDK, so you need to either use Windows SDK 6.x or just copy missing parts from there.
See also:
How to capture frames using Delphi/DSPack without displaying it on TVideoWindow? (Delphi code, but good description and figures)
DirectShow: Examples for Using SampleGrabber for Grabbing a Frame and Building a VU Meter
SetLifeCamStudioResolutionSample - A small DirectShow project showing how to set capture up, including resolution on camera, and Sample Grabber, and also missing SDK declarations; related Q is Can't make IAMStreamConfig.SetFormat() to work with LifeCam Studio
Building the Filter Graph on Sample Grabber and Null Renderer
I think you can include opencv in existing. I've done that for console application. You will need to include path to opencv headers and path to opencv lib in property page for you current project.
Go to project property:
1.To addheaders
C/C++ -----> Additional Include Directories ---> Here add opencv include directories (You may want to include multiples directories)
To add libs
Linker -----> Additional Library Directories ----> Here add opencv lib.
To create IplImage from buf. You can use following once you have the height and width of image.
IplImage *m_img_show;
CvSize cv_img_size = cvSize(m_mediaInfo.m_width, m_mediaInfo.m_height);
m_img_show = cvCreateImageHeader(cv_img_size, IPL_DEPTH_8U,3);
cvSetData(m_img_show, m_pBuffer, m_mediaInfo.m_width*3);
I think preview of image is quite helpful. It seems that your filter above take data from renderer. If you do want you may want to change your renderer and use it in windowless mode. Other option could be to use sample grabber filter.
Related
I am not sure if this is an issue that can be resolved with coding or is by design. I am running the latest version of Windows 11 with all updates. And my application is a MFC dialog application built with Visual Studio 2022.
My application uses a CHtmlView control and the user can trigger a Print Preview. This event will trigger the following code:
void CChristianLifeMinistryHtmlView::DoPrintPreview()
{
ExecWB(OLECMDID_PRINTPREVIEW, OLECMDEXECOPT_PROMPTUSER, nullptr, nullptr);
HWND HWND_PP = nullptr ;
const auto t1 = ::GetTickCount64();
auto t2 = ::GetTickCount64(); // Extra line required for 'while' rearrangement.
while (HWND_PP == nullptr && t2 - t1 <= 6000) // if found or Timeout reached...
{
HWND HWND_FG = ::GetForegroundWindow(); // Get the ForeGroundWindow
if (HWND_FG != nullptr)
{
TCHAR szClassName[256]{} ;
::GetClassName(HWND_FG, &szClassName[0], 256);
if (lstrcmp(&szClassName[0], IE_PPREVIEWCLASS) == 0) // Check for Print Preview Dialog
HWND_PP = HWND_FG ;
}
theApp.PumpMessage();
t2 = ::GetTickCount64();
}
if (HWND_PP != nullptr)
{
RECT workArea{};
::SystemParametersInfo( SPI_GETWORKAREA, 0, &workArea, 0 );
::MoveWindow(HWND_PP, workArea.left, workArea.top,
workArea.right - workArea.left, workArea.bottom - workArea.top, TRUE);
}
}
This code works fine, and I get a good print preview, resized to the display. For example:
Now, if I hit Print from here it displays:
Opting to print to PDF looks the same:
Prior to the recent Windows 11 Updates these latter "print dialogs" looked different with no preview anyway. But since this updated version of the system "print dialog" can cope with a preview, is there no way to get our existing CHtmlView preview displayed there?
This is only a cosmetic thing because I have a standard preview for the user to see anyway (snap 1). But it would be the icing on the cake if that preview could someone be fed into this popup print window.
Is this something we can do by code or is it a "system / by design issue"?
I’m working in C on a project to capture data from a sensor and display it as part of a GUI application on the Raspberry Pi. I am using GTK 3.0, plus Cairo for graphing. I have built an application that works, but I want to make a modification to enable me to change the frequency of data capture.
Within my main code section I have a command like:-
gdk_threads_add_timeout (250, data_capture, widgets);
This all works, the data capture routine is triggered every 250mS, but I want to add functionality to the GUI to enable the user to change the speed. If I try to call this function from anywhere else other than main, it fails.
I have looked for other ways to do it, but I can’t find any examples or explanations of how I can do it.
Ideally what I would like is something like:-
void update_speed(button, widgets)
// Button to change speed has been pressed
read speed from GUI
update frequency
return
int main()
...
setup GUI
set default speed
start main GTK loop
Does anyone have any idea how I could achieve this?
Edit: Additional Code Snippet
(This is not the whole program, but an extract of main)
int main(int argc, char** argv) {
GtkBuilder *builder;
GtkWidget *window;
GError *err = NULL; // holds any error that occurs within GTK
// instantiate structure, allocating memory for it
struct app_widgets *widgets = g_slice_new(struct app_widgets);
// initialise GTK library and pass it in command line parameters
gtk_init(&argc, &argv);
// build the gui
builder = gtk_builder_new();
gtk_builder_add_from_file (builder, "../Visual/gui/main_window.glade", &err);
window = GTK_WIDGET(gtk_builder_get_object(builder, "main_application_window"));
// build the structure of widget pointers
widgets->w_spn_dataspeed = GTK_SPIN_BUTTON(gtk_builder_get_object(builder, "spn_dataspeed"));
widgets->w_spn_refreshspeed = GTK_SPIN_BUTTON(gtk_builder_get_object(builder, "spn_refreshspeed"));
widgets->w_adj_dataspeed = GTK_ADJUSTMENT(gtk_builder_get_object(builder, "adj_dataspeed"));
widgets->w_adj_refreshspeed = GTK_ADJUSTMENT(gtk_builder_get_object(builder, "adj_refreshspeed"));
// connect the widgets to the signal handler
gtk_builder_connect_signals(builder, widgets); // note: second parameter points to widgets
g_object_unref(builder);
// Set a timeout running to refresh the screen
gdk_threads_add_timeout(SCREEN_REFRESH_TIMER, (GSourceFunc)screen_timer_exe, (gpointer)widgets);
gdk_threads_add_timeout(DATA_REFRESH_TIMER, (GSourceFunc)data_timer_exe, (gpointer)widgets);
gtk_widget_show(window);
gtk_main();
// free up memory used by widget structure, probably not necessary as OS will
// reclaim memory from application after it exits
g_slice_free(struct app_widgets, widgets);
return (EXIT_SUCCESS);
I have a standard GDI win32 application. I have a component which can host windowless ActiveX controls (we use this typically for Flash) by utilizing the IOleInPlaceSiteWindowless/IOleInPlaceObjectWindowless pair of interfaces and therefore calling IViewObject::Draw whenever the hosted control calls back into InvalidateRect. This component is generally modeled after this article: http://www.codeguru.com/cpp/com-tech/activex/controls/article.php/c12229/Transparent-Flash-Control-in-Plain-C.htm
Now my application targets some older hardware and I'm seeing some performance problems with this approach that I don't see when running the same ActiveX control in Internet Explorer. In fact, using process monitor, I'm able to see that IE is using the GPU to some degree to render while my application is not. This has led me to discover that IE is likely using DirectDraw under the covers the achieve the better performance.
So I've taken a stab at doing this within my application, but I'm not seeing anything drawn on the screen. My DirectX/DirectDraw knowledge is nearly nil so that may have something to do with it, but here is what I'm trying to do. Maybe someone can see what I'm doing wrong and get me to where I need to be (note that I am just playing around which is why there is no error handling):
I create my layered window
ivhWnd = CreateWindowEx(WS_EX_LAYERED,
L"MyWndClass",
NULL,
WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
ivhParentWindow,
( HMENU )NULL,
ivhAppInstance,
( LPVOID )NULL );
I initialize DirectDraw and create an off screen surface:
DirectDrawCreateEx(NULL, (LPVOID*)&pivDD, IID_IDirectDraw7, NULL);
pivDD->SetCooperativeLevel(NULL, DDSCL_NORMAL);
DDSURFACEDESC2 tvSurfDesc;
ZeroMemory(&tvSurfDesc, sizeof(DDSURFACEDESC2));
tvSurfDesc.dwSize = sizeof(DDSURFACEDESC2);
tvSurfDesc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
tvSurfDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
tvSurfDesc.dwWidth = 320;
tvSurfDesc.dwHeight = 340;
HRESULT tvHR = pivDD->CreateSurface((LPDDSURFACEDESC)&tvSurfDesc, (LPDIRECTDRAWSURFACE*)&pivPrimarySurface, NULL);
LPDIRECTDRAWCLIPPER ptvClipper;
pivDD->CreateClipper(0, &ptvClipper, NULL);
ptvClipper->SetHWnd(0, ivhInternalMsgWindow);
pivPrimarySurface->SetClipper(ptvClipper);
Similar to my initial implementation where I called IViewObject::Draw whenever InvalidateRect is called by the control; I now do basically the same, but utilizing the DC for my DDraw surface instead of a compatible bitmap:
RECT rTotal;
::GetClientRect(ivhWnd, &rTotal);
HDC tvhDC;
pivPrimarySurface->GetDC(&tvhDC);
HRESULT tvHR = OleDraw(ivViewObject, DVASPECT_TRANSPARENT, tvhDC, &rTotal);
BLENDFUNCTION bf;
bf.BlendOp = AC_SRC_OVER;
bf.AlphaFormat = AC_SRC_ALPHA;
bf.BlendFlags = 0;
bf.SourceConstantAlpha = 255;
UpdateLayeredWindow(ivhWnd, NULL, NULL, NULL, tvhDC, NULL, 0, &bf, ULW_ALPHA);
Not sure what I'm doing wrong, and I'm basically stuck. Any help would be appreciated.
I'm a little new to using MFC and VC++ as such, but I'm doing this as part of a Course and i Have to stick to VC++.
http://www.cprogramming.com/tutorial/game_programming/same_game_part1.html
This is the tutorial I have been following to make a simple samegame. However when i try to display score, the score is getting displayed Underneath or outside my application window, even though I've displayed score before calling updateWindow(). I've tried various methods but I am kinda lost here.
Here is the code I'm using to Display the score:
void CSameGameView::updateScore()
{
CSameGameDoc* pDoc = GetDocument();
CRect rcClient, rcWindow;
GetClientRect(&rcClient);
GetParentFrame()->GetWindowRect(&rcWindow);
int nHeightDiff = rcWindow.Height() - rcClient.Height();
rcScore.top=rcWindow.top + pDoc->GetHeight() * pDoc->GetRows() + nHeightDiff;
rcScore.left=rcWindow.left + 50;
rcScore.right=rcWindow.left + pDoc->GetWidth() - 50;
rcScore.bottom=rcScore.top + 20;
CString str;
double points = Score::getScore();
str.Format(_T("Score: %0.2f"), points);
HDC hDC=CreateDC(TEXT("DISPLAY"),NULL,NULL,NULL);
COLORREF clr = pDoc->GetBoardSpace(-1, -1); //this return background colour
pDC->FillSolidRect(&rcScore, clr);
DrawText(hDC, (LPCTSTR) str, -1, (LPRECT) &rcScore, DT_CENTER);
}
Thank you for any help and I'm sorry if the question doesn't make sense or in ambiguous.
There are several problems with your code:
1. The hDC you are creating is going to have coordinates relative to the desktop window. To paint text in your window, use CClientDC like this: CClientDC dc(this); (see http://msdn.microsoft.com/en-US/library/s8kx4w44%28v=vs.80%29.aspx)
2. The code you have will leak a DC every time the function is called. The method in #1 will fix that.
3. Your paint code should be done in the CView::OnDraw. There you get a DC passed to you and you don't have to worry about creating one with CClientDC. Set the variables you want to draw (e.g. your points or score), store them as class members and draw them in CView::OnDraw.
Don't do the drawing in your updateScore method.
Make sense? Hang in there!
I have an MDI MFC FEATURE PACK app in vs2008.
I do need to determine what child window(s) are visible , even if multiple tab groups are created by the user, and also what is the last activated MDI child. I have found that in my mainframe CMDIFrameWndEx class, the methods
m_wndClientArea.FindActiveTabWnd ();
m_wndClientArea.GetFirstTabWnd ();
m_wndClientArea.GetNextTabWnd ();
that could potentially let me navigate through all tab grops. Trouble is that these methods return an CMFCTabControl that does not offer any method/member to obtain an pointer to the MDI child windows in the tab. It only gives the index of the active tab.
So how do I get the CMDIChildWndEx* pointer of the "in front" window of the given tabgroup?
Because your CMDIChildWndEx instances are wrapped in a tab control wrapper you can get the active tab and then the wnd from that, e.g.
int nActive = pTabCtrl->GetActiveTab();
CWnd * pWnd = pTabCtrl->GetTabWndNoWrapper( nActive );
CMDIChildWndEx * pChild = dynamic_cast<CMDIChildWndEx*>(pWnd);
It was wonderful to find this code - exactly what I needed to redraw my active tab windows in each tab group since with multiple (split) tab groups, they were not being redrawn correctly. However, to make the loop work I had to do the following (CChildFrame is my derived frame type):
m_arrpActiveChilds.RemoveAll ();
const CObList& TabGroups =m_wndClientArea.GetMDITabGroups();
if (TabGroups.GetCount ()>0) {
POSITION crtPos = TabGroups.GetHeadPosition ();
CMFCTabCtrl* pCrtTabCtrl;
do {
pCrtTabCtrl=DYNAMIC_DOWNCAST(CMFCTabCtrl, TabGroups.GetNext(crtPos));
int nActive = pCrtTabCtrl->GetActiveTab();
CWnd * pWnd = pCrtTabCtrl->GetTabWndNoWrapper( nActive );
CChildFrame * pChild = dynamic_cast<CChildFrame*>(pWnd);
m_arrpActiveChilds.Add (pChild);
} while(crtPos != NULL);