CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 14 of 14
  1. #1
    Join Date
    Jan 2009
    Posts
    399

    Convert console into SDI

    Hi all of you. I came here because I get always help here, and I am stuck into relative simple issue: to convert a console program, into a real life SDI MFC app, an program that embed OpenCV library.

    I have taken from here the sample program: https://www.youtube.com/watch?v=A4UDOAOTRdw

    And here is the code, simplified:
    Code:
    int main(void)
    {
    cv::VideoCapture capVideo;
    
    cv::Mat imgFrame1;
    cv::Mat imgFrame2;
    
    std::vector<Blob> blobs;
    
    capVideo.open("768x576.avi");
    
    capVideo.read(imgFrame1);
    capVideo.read(imgFrame2);
    
    char chCheckForEscKey = 0;
    
    bool blnFirstFrame = true;
    
    int frameCount = 2;
    
    while (capVideo.isOpened() && chCheckForEscKey != 27)
    {
        std::vector<Blob> currentFrameBlobs;
    
        cv::Mat imgFrame1Copy = imgFrame1.clone();
        cv::Mat imgFrame2Copy = imgFrame2.clone();
    
        // image processing (simplified code)
    
        imgFrame2Copy = imgFrame2.clone();          // get another copy of frame 2 since we changed the previous frame 2 copy in the processing above
    
        drawBlobInfoOnImage(blobs, imgFrame2Copy);
    
        cv::imshow("imgFrame2Copy", imgFrame2Copy);
    
        // now we prepare for the next iteration
        currentFrameBlobs.clear();
        imgFrame1 = imgFrame2.clone();           // move frame 1 up to where frame 2 is
    
        if ((capVideo.get(CV_CAP_PROP_POS_FRAMES) + 1) < capVideo.get(CV_CAP_PROP_FRAME_COUNT))
        {
            capVideo.read(imgFrame2);
        }
    
        blnFirstFrame = false;
        frameCount++;
        chCheckForEscKey = cv::waitKey(1);
    }
    
    return(0);
    }
    and here is the result:
    Name:  KaixV.jpg
Views: 441
Size:  29.2 KB
    Now, I have tried to made some similar in MFC:
    Code:
        class CMyDoc : public CDocument
    {
    // Attributes
    public:
        cv::Mat m_Mat;    // this will be rendered in CView !!!
    ....
    and
    Code:
        protected:
        BOOL m_bFirstFrame;
        cv::Mat m_Mat1, m_Mat2;
        cv::VideoCapture m_Video;
        std::vector<CBlob> m_blobs;
    and the implementation code is simple:
    Code:
        void CMyDoc::ShowNextFrame()    // called at some time interval, when FPS rate is request this
    {
        if(m_Video.isOpened())
        {
            m_Video.read(m_Mat);
            DrawVideoImageSubtractionAndCount();
        }
    }
    And here is the buggy DrawVideoImageSubtractionAndCount:
    Code:
        void CMyDoc::DrawVideoImageSubtractionAndCount()
    {
        if(m_bFirstFrame)
        {
            m_Video.read(m_Mat1);
            m_Video.read(m_Mat2);
        }
    
        // image processing
    
        Mat2Copy = m_Mat2.clone();          // get another copy of frame 2 since we changed the previous frame 2 copy in the processing above
        DrawBlobInfoOnImage(m_blobs, Mat2Copy);
        m_Mat = Mat2Copy.clone();
    
        m_Mat1 = m_Mat2.clone();
        m_Video.read(m_Mat2);
    
        m_bFirstFrame = FALSE;
    }
    and here is the result of my MFC:
    Name:  CETnE.jpg
Views: 454
Size:  30.7 KB
    Can you tell me how to handle m_Mat in order to have the right result ?

    Thank you for any hint/solution.

  2. #2
    Join Date
    Aug 2006
    Posts
    231

    Re: Convert console into SDI

    Hi, can you explain where the view is updated in your MFC code? I don't see any call to the view, or any call like imshow that was used in your first example.

    And why do you need this line?

    Code:
    m_Video.read(m_Mat)
    As far as I can tell, m_Mat will not be used before it's reassigned inside DrawVideoImageSubtractionAndCount, so it looks like it will just skip a frame.

  3. #3
    Join Date
    Jan 2009
    Posts
    399

    Re: Convert console into SDI

    Hi TubularX, and thank you for your answer.

    Here is the rendering moments:

    Code:
    //  OnDraw method
    void CMyView::OnDraw(CDC* pDC)
    {
    ....
    	pDC->BitBlt(0, 0, rectClient.Width(), rectClient.Height(), &memDC, 0, 0, SRCCOPY);    //<-- basically, here is rendering pDoc->m_Mat object
    }
    and
    Code:
    // is the moment when OnDraw is fired, in OnTimer method
    void CMyView::OnTimer(UINT_PTR nIDEvent)
    {
    	// TODO: Add your message handler code here and/or call default
    
    	CView::OnTimer(nIDEvent);
    
    	if(ID_TIMER_RENDER == nIDEvent)
    	{
    		CMyDoc* pDoc = GetDocument();
    		pDoc->ShowNextFrame();       // <-- See CMyDoc::ShowNextFrame() from below
    		pDoc->UpdateAllViews(NULL); // <-- Basically, here is called CMyView::OnDraw
    	}
    }
    and the time when ID_TIMER_RENDER is set up is here:
    Code:
    void CMyDoc::ShowNextFrame()
    {
    	if(m_Video.isOpened())
    	{
    		m_Video.read(m_Mat);
    		DrawVideoImageSubtractionAndCount();
    	}
    
    	int nIndex = static_cast<int>(m_Video.get(CV_CAP_PROP_POS_FRAMES));
    	int nTotal = static_cast<int>(m_Video.get(CV_CAP_PROP_FRAME_COUNT));
    
    	if(nIndex >= nTotal)
    	{
    		CView* pView = NULL;
    		POSITION pos = GetFirstViewPosition();
    		while(NULL != pos)
    		{
    			pView = GetNextView(pos);
    			::PostMessage(pView->GetSafeHwnd(), WMU_SETFPS, 0, 0);
    		}
    	}
    }
    and
    Code:
    // the handler for WMU_SETFPS
    LRESULT CMyView::OnSetfps(WPARAM wParam, LPARAM lParam)
    {
    	if(static_cast<int>(wParam) <= 0)
    		KillTimer(ID_TIMER_RENDER);
    	else
    		SetTimer(ID_TIMER_RENDER, static_cast<UINT>(wParam), NULL);
    
    	return 1;
    }
    Please tell me if you need mode details ! I really appreciate your attention !!
    Last edited by mesajflaviu; July 10th, 2018 at 06:47 AM.

  4. #4
    Join Date
    Aug 2006
    Posts
    231

    Re: Convert console into SDI

    My guess would be that you need to clear the m_blobs vector after every frame, otherwise all blobs will be drawn for every frame (see the call to drawBlobInfoOnImage). This is based on the assumption that the blobs contain the rectangles and numbers that are drawn.

    Or if you already clear it, can you post that code and show where the blob vector is populated.
    Last edited by TubularX; July 10th, 2018 at 07:50 AM.

  5. #5
    Join Date
    Jan 2009
    Posts
    399

    Re: Convert console into SDI

    I have already tried that, but then the algorithm is not goes well.

    Here is the code where m_blobs is handled:
    Code:
    	if(! m_bFirstFrame)
    		MatchCurrentFrameBlobsToExistingBlobs(m_blobs, currentFrameBlobs);
    	else
    	{
    		for(std::vector<CBlob>::iterator it = currentFrameBlobs.begin();it != currentFrameBlobs.end();++it)
    			m_blobs.push_back(*it);
    	}
    As you can see, if currentFrameBlobs is match with m_blobs, then currentFrameBlobs is added on m_blobs ...
    here is the original console code:
    Code:
            if (blnFirstFrame == true) {
                for (auto &currentFrameBlob : currentFrameBlobs) {
                    blobs.push_back(currentFrameBlob);
                }
            } else {
                matchCurrentFrameBlobsToExistingBlobs(blobs, currentFrameBlobs);
            }
    but std::vector<Blob> blobs; is declared outside of while(1) looping ... that is the reason I declared as CMyDocument member variable.

  6. #6
    Join Date
    Jan 2009
    Posts
    399

    Re: Convert console into SDI

    And here is the MatchCurrentFrameBlobsToExistingBlobs method implementation:
    Code:
    void CMyDoc::MatchCurrentFrameBlobsToExistingBlobs(std::vector<CBlob>& existingBlobs, std::vector<CBlob>& currentFrameBlobs)
    {
    	for(std::vector<CBlob>::iterator it = existingBlobs.begin();it != existingBlobs.end();++it)
    	{
    		CBlob iteratorBlob = *it;
    		iteratorBlob.m_bCurrentMatchFoundOrNewBlob = FALSE;
    		iteratorBlob.PredictNextPosition();
    	}
    	for(std::vector<CBlob>::iterator it = currentFrameBlobs.begin();it != currentFrameBlobs.end();++it)
    	{
    		CBlob iteratorBlob = *it;
    		int nIndexOfLeastDistance = 0;
    		double dLeastDistance = 100000;
    		for (unsigned int i = 0;i < existingBlobs.size();++i)
    		{
    			if(existingBlobs[i].m_bStillBeingTracked)
    			{
    				double dDistance = DistanceBetweenPoints(iteratorBlob.m_vecPointCenterPositions.back(), existingBlobs[i].m_ptPredictedNextPosition);
    				if(dDistance < dLeastDistance)
    				{
    					dLeastDistance = dDistance;
    					nIndexOfLeastDistance = i;
    				}
    			}
    		}
    		if (dLeastDistance < iteratorBlob.m_dCurrentDiagonalSize * 1.15)
    			AddBlobToExistingBlobs(iteratorBlob, existingBlobs, nIndexOfLeastDistance);
    		else
    			AddNewBlob(iteratorBlob, existingBlobs);
    	}
    	for(std::vector<CBlob>::iterator it = existingBlobs.begin();it != existingBlobs.end();++it)
    	{
    		CBlob iteratorBlob = *it;
    		if(! iteratorBlob.m_bCurrentMatchFoundOrNewBlob)
    			iteratorBlob.m_nNumOfConsecutiveFramesWithoutAMatch++;
    		if(iteratorBlob.m_nNumOfConsecutiveFramesWithoutAMatch >= 5)
    			iteratorBlob.m_bStillBeingTracked = FALSE;
    	}
    }

  7. #7
    Join Date
    Aug 2006
    Posts
    231

    Re: Convert console into SDI

    OK, I see a problem here. You're creating a copy of each blob, and then you modify the copy. The blob inside the vector is not updated.

    Code:
    CBlob iteratorBlob = *it;
    iteratorBlob.m_bCurrentMatchFoundOrNewBlob = FALSE;
    You need to use a pointer or a reference (in all the loops inside MatchCurrentFrameBlobsToExistingBlobs).
    Last edited by TubularX; July 11th, 2018 at 09:46 AM.

  8. #8
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,822

    Re: Convert console into SDI

    Why not just use a range-based for loop? Something like this (not tried) for the first loop (assuming your compiler is at least c++11 compliant)

    Code:
    for (auto& Blob : existingBlobs)
    { 
        Blob.m_bCurrentMatchFoundOrNewBlob = FALSE;
        Blob.PredictNextPosition();
    }
    and similarly for the other existing iterator loops.
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  9. #9
    Join Date
    Jan 2009
    Posts
    399

    Re: Convert console into SDI

    Ok, I modified as it follow:
    Code:
    	for(std::vector<CBlob>::iterator it = existingBlobs.begin();it != existingBlobs.end();++it)
    	{
    		it->m_bCurrentMatchFoundOrNewBlob = FALSE;
    		it->PredictNextPosition();
    	}
    and the MatchCurrentFrameBlobsToExistingBlobs is looking like that:
    Code:
    void CMyDoc::MatchCurrentFrameBlobsToExistingBlobs(std::vector<CBlob>& existingBlobs, std::vector<CBlob>& currentFrameBlobs)
    {
    	for(std::vector<CBlob>::iterator it = existingBlobs.begin();it != existingBlobs.end();++it)
    	{
    		it->m_bCurrentMatchFoundOrNewBlob = FALSE;
    		it->PredictNextPosition();
    	}
    	for(std::vector<CBlob>::iterator it = currentFrameBlobs.begin();it != currentFrameBlobs.end();++it)
    	{
    		int nIndexOfLeastDistance = 0;
    		double dLeastDistance = 100000;
    		for (unsigned int i = 0;i < existingBlobs.size();++i)
    		{
    			if(existingBlobs[i].m_bStillBeingTracked)
    			{
    				double dDistance = DistanceBetweenPoints(it->m_vecPointCenterPositions.back(), existingBlobs[i].m_ptPredictedNextPosition);
    				if(dDistance < dLeastDistance)
    				{
    					dLeastDistance = dDistance;
    					nIndexOfLeastDistance = i;
    				}
    			}
    		}
    		if (dLeastDistance < it->m_dCurrentDiagonalSize * 1.15)
    			AddBlobToExistingBlobs(*it, existingBlobs, nIndexOfLeastDistance);
    		else
    			AddNewBlob(*it, existingBlobs);
    	}
    	for(std::vector<CBlob>::iterator it = existingBlobs.begin();it != existingBlobs.end();++it)
    	{
    		if(! it->m_bCurrentMatchFoundOrNewBlob)
    			it->m_nNumOfConsecutiveFramesWithoutAMatch++;
    		if(it->m_nNumOfConsecutiveFramesWithoutAMatch >= 5)
    			it->m_bStillBeingTracked = FALSE;
    	}
    }
    I guess it is ok now ... I didn't worked with containers by now ... of course, this is not excuse, I should know what I have done.
    Last edited by mesajflaviu; July 12th, 2018 at 05:37 AM.

  10. #10
    Join Date
    Jan 2009
    Posts
    399

    Re: Convert console into SDI

    Hi 2kaud. I am working in VS2010, and I've tried that:
    Code:
    	for(auto& it : existingBlobs)
    	{
    	}
    and I get errors:
    Code:
    error C2143: syntax error : missing ',' before ':'
    error C2530: 'it' : references must be initialized
    error C3531: 'it': a symbol whose type contains 'auto' must have an initializer
    error C2143: syntax error : missing ';' before '{'

  11. #11
    Join Date
    Jan 2009
    Posts
    399

    Re: Convert console into SDI

    TubularX, seem to work !!!!

    You make my day, my week, my month ! With your attention, looking over my code, you did sooo much ! Kindly thank you !!

  12. #12
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,822

    Re: Convert console into SDI

    Quote Originally Posted by mesajflaviu View Post
    Hi 2kaud. I am working in VS2010,
    VS2010 is 8 years old and doesn't support even the c++11 standard - only the outdated c++03 (which is basically just c++98). You should really consider upgrading your compiler to the latest VS2017 which supports the current c++17 standard.
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  13. #13
    Join Date
    Aug 2006
    Posts
    231

    Re: Convert console into SDI

    You're welcome.

    Like 2kaud said, it would be a good idea to upgrade your compiler.

    As a side note, you should be able to make your code more efficient by replacing:

    Code:
    Mat2Copy = m_Mat2.clone();
    DrawBlobInfoOnImage(m_blobs, Mat2Copy);
    m_Mat = Mat2Copy.clone();
    with

    Code:
    m_Mat = m_Mat2.clone();
    DrawBlobInfoOnImage(m_blobs, m_Mat);

  14. #14
    Join Date
    Jan 2009
    Posts
    399

    Re: Convert console into SDI

    Quote Originally Posted by TubularX View Post
    You're welcome.

    As a side note, you should be able to make your code more efficient by replacing:

    Code:
    Mat2Copy = m_Mat2.clone();
    DrawBlobInfoOnImage(m_blobs, Mat2Copy);
    m_Mat = Mat2Copy.clone();
    with

    Code:
    m_Mat = m_Mat2.clone();
    DrawBlobInfoOnImage(m_blobs, m_Mat);
    You are perfectly right, in fact, that was the original code (I wrote the code exactly how you said), but I made a Map2Copy temporary object in order to reproduce the original code, in my un-numbered trials to solve the problem ...

    I am very glad of you attention !!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured