Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
CODE PROJECT For Those Who Code
  • Home
  • Articles
  • FAQ
Community
  1. Home
  2. General Programming
  3. C / C++ / MFC
  4. How to threshold an image?

How to threshold an image?

Scheduled Pinned Locked Moved C / C++ / MFC
questionc++hardwaretutorial
13 Posts 5 Posters 1 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • U uus99

    Hi there, i'm doing image processing in VC++6. How can i perform thresholding (converting color to b&w) on an image, as fast as possible? I'm able to do using GetPixel & SetPixel but it is too slow. Anyway i can access the pixels directly?? Here is the code //Image width=height=Big=360 px int Big=360; //Create a DC for buffering image CDC MemDC,*pDC; CBitmap MemBitmap; // Get Current DC from dialog box, pDC = myDlg->GetDC(); MemDC.CreateCompatibleDC(pDC); // MemBitmap.CreateCompatibleBitmap(pDC,Big,Big); CBitmap *pOldBitmap = MemDC.SelectObject(&MemBitmap); //------------custom hardware function that draws image from camera to DC-----------// imgPlot ((GUIHNDL)MemDC.GetSafeHdc(), (void *)ImaqBuffer, 0, 0, Big, Big, 410, 10, plotFlag)); //------------------------------------------- //My thresholding function, which is very slow!!! //check every pixel, if it is bigger than threshold then turn it black //and white otherwise //********** for(int i=0;i<360;i++) for(int j=0;j<360;j++) { if(MemDC->GetPixel(i,j)<=RGB(64,128,255)) MemDC->SetPixel(i,j,RGB(0,0,0)); else MemDC->SetPixel(i,j,RGB(255,255,255)); } pDC->BitBlt(10,10,Big,Big,&MemDC,0,0,SRCCOPY); //See Note 3 MemDC.SelectObject(pOldBitmap); //--------------------------- The code is too slow for real time. How can i do thresholding faster?

    C Offline
    C Offline
    cmk
    wrote on last edited by
    #4

    On a tangent : How did you come up with RGB(64,128,255) as a B&W threshold color ? I would have expected to take the pixel color, get its grey value, and check that against a threshold value of 128 (or whatever). e.g.

    byte grey = (byte)(
    (R * 0.299) +
    (G * 0.587) +
    (B * 0.114)
    );

    ...cmk Save the whales - collect the whole set

    1 Reply Last reply
    0
    • U uus99

      Hi there, i'm doing image processing in VC++6. How can i perform thresholding (converting color to b&w) on an image, as fast as possible? I'm able to do using GetPixel & SetPixel but it is too slow. Anyway i can access the pixels directly?? Here is the code //Image width=height=Big=360 px int Big=360; //Create a DC for buffering image CDC MemDC,*pDC; CBitmap MemBitmap; // Get Current DC from dialog box, pDC = myDlg->GetDC(); MemDC.CreateCompatibleDC(pDC); // MemBitmap.CreateCompatibleBitmap(pDC,Big,Big); CBitmap *pOldBitmap = MemDC.SelectObject(&MemBitmap); //------------custom hardware function that draws image from camera to DC-----------// imgPlot ((GUIHNDL)MemDC.GetSafeHdc(), (void *)ImaqBuffer, 0, 0, Big, Big, 410, 10, plotFlag)); //------------------------------------------- //My thresholding function, which is very slow!!! //check every pixel, if it is bigger than threshold then turn it black //and white otherwise //********** for(int i=0;i<360;i++) for(int j=0;j<360;j++) { if(MemDC->GetPixel(i,j)<=RGB(64,128,255)) MemDC->SetPixel(i,j,RGB(0,0,0)); else MemDC->SetPixel(i,j,RGB(255,255,255)); } pDC->BitBlt(10,10,Big,Big,&MemDC,0,0,SRCCOPY); //See Note 3 MemDC.SelectObject(pOldBitmap); //--------------------------- The code is too slow for real time. How can i do thresholding faster?

      U Offline
      U Offline
      uus99
      wrote on last edited by
      #5

      John >>Can you get the hardware to give you a pointer to the image data instead of ploting it to a dc? The pointer to the image buffer is (void *)ImaqBuffer, however, i do not know the structure of data in it. The only way i can access it is by plotting to DC. >>I would have expected to take the pixel color, get its grey value, and check that against a threshold value of 128 (or whatever). I know, my comparison is just too crude. Thanks. I'll try that, but i still have to check all the pixels using SetPixel & GetPixel which is too slow. I need it fast. >>Haven't messed with bitmaps in a while, but try GetBitmapBits(), which will give you an array of bytes containing the bitmap. Then run through this array changing values. Then call SetBitmapBits() with the modified array. This should be much faster. I havent try this, but i will. I'll see how fast it is. Btw, i've tried this. 1. Open a color bmp from disk and change it to B&W using LR_MONOCHROME 2. Open a color bmp, load into DC and do setpixel and getpixel. The first method is way faster.. How come? I need a way to convert that fast. But, i want to do everything in memory to overcome disk read overhead. Although, in this case, the 1 method is still faster, although i'm reading from disk.

      1 Reply Last reply
      0
      • U uus99

        Hi there, i'm doing image processing in VC++6. How can i perform thresholding (converting color to b&w) on an image, as fast as possible? I'm able to do using GetPixel & SetPixel but it is too slow. Anyway i can access the pixels directly?? Here is the code //Image width=height=Big=360 px int Big=360; //Create a DC for buffering image CDC MemDC,*pDC; CBitmap MemBitmap; // Get Current DC from dialog box, pDC = myDlg->GetDC(); MemDC.CreateCompatibleDC(pDC); // MemBitmap.CreateCompatibleBitmap(pDC,Big,Big); CBitmap *pOldBitmap = MemDC.SelectObject(&MemBitmap); //------------custom hardware function that draws image from camera to DC-----------// imgPlot ((GUIHNDL)MemDC.GetSafeHdc(), (void *)ImaqBuffer, 0, 0, Big, Big, 410, 10, plotFlag)); //------------------------------------------- //My thresholding function, which is very slow!!! //check every pixel, if it is bigger than threshold then turn it black //and white otherwise //********** for(int i=0;i<360;i++) for(int j=0;j<360;j++) { if(MemDC->GetPixel(i,j)<=RGB(64,128,255)) MemDC->SetPixel(i,j,RGB(0,0,0)); else MemDC->SetPixel(i,j,RGB(255,255,255)); } pDC->BitBlt(10,10,Big,Big,&MemDC,0,0,SRCCOPY); //See Note 3 MemDC.SelectObject(pOldBitmap); //--------------------------- The code is too slow for real time. How can i do thresholding faster?

        R Offline
        R Offline
        Ryan Binns
        wrote on last edited by
        #6

        Try creating a monochrome bitmap, and do a BitBlt() from the colour one to the monochrome one - let Windows do all the work for you. It doesn't give you control over the threshold, but might be adequate for what you need.

        Ryan

        "Punctuality is only a virtue for those who aren't smart enough to think of good excuses for being late" John Nichol "Point Of Impact"

        1 Reply Last reply
        0
        • J J Eric Vaughan

          Haven't messed with bitmaps in a while, but try GetBitmapBits(), which will give you an array of bytes containing the bitmap. Then run through this array changing values. Then call SetBitmapBits() with the modified array. This should be much faster. ____________________________________________ Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning. (Rich Cook)

          U Offline
          U Offline
          uus99
          wrote on last edited by
          #7

          Hi there, can you give me an example of using the GetBitmapBits()? I cant find any example on it.

          J 1 Reply Last reply
          0
          • U uus99

            Hi there, can you give me an example of using the GetBitmapBits()? I cant find any example on it.

            J Offline
            J Offline
            J Eric Vaughan
            wrote on last edited by
            #8

            This is copied from a test app I wrote (real quick, so don't be too critical - it works).

                CPaintDC dc(this);
                CRect cRect; GetClientRect( cRect );
                int nWidth = cRect.Width();
                int nHeight = cRect.Height();
                CBitmap cBitmap;
            
                cBitmap.LoadBitmap( IDB\_BITMAP1 );
            
                DWORD\* pBuffer = new DWORD\[ nWidth \* nHeight \];
            
            
                DWORD dwSize = cBitmap.GetBitmapBits( nWidth \* nHeight,
                                                    pBuffer );
                for ( int y = 0 ; y < nHeight ; y++ )
                {
                    for ( int x = 0; x < nWidth ; x++ )
                    {
                        if ( \*(pBuffer+x+nWidth\*y) < RGB( 64, 128 , 256 ) )
                        {
                            \*(pBuffer+x+nWidth\*y) = 0; //black
                        }
                        else
                        {
                            \*(pBuffer+x+nWidth\*y) = 0x00FFFFFF; //white
                        }
                    }
                }
            
                cBitmap.SetBitmapBits( nWidth \* nHeight ,
                                       pBuffer );
            
                CDC cMemDC;
                cMemDC.CreateCompatibleDC( &dc );
            
                cMemDC.SelectObject( &cBitmap );
            
                dc.BitBlt( 0,
                           0,
                           nWidth,
                           nHeight,
                           &cMemDC,
                           0,
                           0,
                           SRCCOPY );
            
            
                delete \[\] pBuffer;
            
            U 1 Reply Last reply
            0
            • J J Eric Vaughan

              This is copied from a test app I wrote (real quick, so don't be too critical - it works).

                  CPaintDC dc(this);
                  CRect cRect; GetClientRect( cRect );
                  int nWidth = cRect.Width();
                  int nHeight = cRect.Height();
                  CBitmap cBitmap;
              
                  cBitmap.LoadBitmap( IDB\_BITMAP1 );
              
                  DWORD\* pBuffer = new DWORD\[ nWidth \* nHeight \];
              
              
                  DWORD dwSize = cBitmap.GetBitmapBits( nWidth \* nHeight,
                                                      pBuffer );
                  for ( int y = 0 ; y < nHeight ; y++ )
                  {
                      for ( int x = 0; x < nWidth ; x++ )
                      {
                          if ( \*(pBuffer+x+nWidth\*y) < RGB( 64, 128 , 256 ) )
                          {
                              \*(pBuffer+x+nWidth\*y) = 0; //black
                          }
                          else
                          {
                              \*(pBuffer+x+nWidth\*y) = 0x00FFFFFF; //white
                          }
                      }
                  }
              
                  cBitmap.SetBitmapBits( nWidth \* nHeight ,
                                         pBuffer );
              
                  CDC cMemDC;
                  cMemDC.CreateCompatibleDC( &dc );
              
                  cMemDC.SelectObject( &cBitmap );
              
                  dc.BitBlt( 0,
                             0,
                             nWidth,
                             nHeight,
                             &cMemDC,
                             0,
                             0,
                             SRCCOPY );
              
              
                  delete \[\] pBuffer;
              
              U Offline
              U Offline
              uus99
              wrote on last edited by
              #9

              Thanks a lot for the help. Looking at the code you gave me, seems that it would be faster than the one i just figured out, :P i havent try your code yet, coz i just got wrote myself a working code. Here is the code that i wrote, //the test image "bmptest.bmp" is a color bmp 360x360 pixels ------------------------------------------ CDC *pDC; CDC memDCLoad; CBitmap m_bmpBitmap; pDC = this->GetDC(); CString m_sBitmap; m_sBitmap="bmptest.bmp"; memDCLoad.CreateCompatibleDC(pDC); HBITMAP hBitmap =(HBITMAP)::LoadImage(AfxGetInstanceHandle(),m_sBitmap,IMAGE_BITMAP,0,0, LR_LOADFROMFILE|LR_DEFAULTCOLOR); if(hBitmap) { if(m_bmpBitmap.DeleteObject()) m_bmpBitmap.Detach(); m_bmpBitmap.Attach(hBitmap); } memDCLoad.SelectObject(&m_bmpBitmap); pDC->BitBlt(0,0,360,360,&memDCLoad,0,0,SRCCOPY); BYTE test[(4*360*360)]; void* pbBits = test;// One bit per pixel m_bmpBitmap.GetBitmapBits(4*360*360, &pbBits); for(int i=0;i<360*360;i++) { //BGR=000 //black //BGR=255,255,255//white int temp=i*4; //test[temp+0]=0;//blue //test[temp+1]=0;//green //test[temp+2]=0;//red //test[temp+3]=255;//padding BYTE gray= (byte)(test[temp+2]*0.299 +test[temp+1]*0.587 +test[temp+0]*0.114); if(gray<=230) { test[temp+0]=0;//blue test[temp+1]=0;//green test[temp+2]=0;//red } else { test[temp+0]=255;//blue test[temp+1]=255;//green test[temp+2]=255;//red } } m_bmpBitmap.SetBitmapBits(4*360*360, &pbBits); pDC->BitBlt(360,0,360,360,&memDCLoad,0,0,SRCCOPY);

              J 1 Reply Last reply
              0
              • U uus99

                Thanks a lot for the help. Looking at the code you gave me, seems that it would be faster than the one i just figured out, :P i havent try your code yet, coz i just got wrote myself a working code. Here is the code that i wrote, //the test image "bmptest.bmp" is a color bmp 360x360 pixels ------------------------------------------ CDC *pDC; CDC memDCLoad; CBitmap m_bmpBitmap; pDC = this->GetDC(); CString m_sBitmap; m_sBitmap="bmptest.bmp"; memDCLoad.CreateCompatibleDC(pDC); HBITMAP hBitmap =(HBITMAP)::LoadImage(AfxGetInstanceHandle(),m_sBitmap,IMAGE_BITMAP,0,0, LR_LOADFROMFILE|LR_DEFAULTCOLOR); if(hBitmap) { if(m_bmpBitmap.DeleteObject()) m_bmpBitmap.Detach(); m_bmpBitmap.Attach(hBitmap); } memDCLoad.SelectObject(&m_bmpBitmap); pDC->BitBlt(0,0,360,360,&memDCLoad,0,0,SRCCOPY); BYTE test[(4*360*360)]; void* pbBits = test;// One bit per pixel m_bmpBitmap.GetBitmapBits(4*360*360, &pbBits); for(int i=0;i<360*360;i++) { //BGR=000 //black //BGR=255,255,255//white int temp=i*4; //test[temp+0]=0;//blue //test[temp+1]=0;//green //test[temp+2]=0;//red //test[temp+3]=255;//padding BYTE gray= (byte)(test[temp+2]*0.299 +test[temp+1]*0.587 +test[temp+0]*0.114); if(gray<=230) { test[temp+0]=0;//blue test[temp+1]=0;//green test[temp+2]=0;//red } else { test[temp+0]=255;//blue test[temp+1]=255;//green test[temp+2]=255;//red } } m_bmpBitmap.SetBitmapBits(4*360*360, &pbBits); pDC->BitBlt(360,0,360,360,&memDCLoad,0,0,SRCCOPY);

                J Offline
                J Offline
                J Eric Vaughan
                wrote on last edited by
                #10

                My inner loop could be much simpler and faster:

                   for ( int x = 0 ; x < dwSize ; x++ ) 
                   {
                        if ( pBuffer\[x\] < RGB( 64, 128 , 256 ) )
                        {
                            pBuffer\[x\] = 0; //black
                        }
                        else
                        {
                            pBuffer\[x\] = 0x00FFFFFF; //white
                        }
                    }
                

                I was thinking two-dimensions, but it's really just one one big buffer :doh:

                U 1 Reply Last reply
                0
                • J J Eric Vaughan

                  My inner loop could be much simpler and faster:

                     for ( int x = 0 ; x < dwSize ; x++ ) 
                     {
                          if ( pBuffer\[x\] < RGB( 64, 128 , 256 ) )
                          {
                              pBuffer\[x\] = 0; //black
                          }
                          else
                          {
                              pBuffer\[x\] = 0x00FFFFFF; //white
                          }
                      }
                  

                  I was thinking two-dimensions, but it's really just one one big buffer :doh:

                  U Offline
                  U Offline
                  uus99
                  wrote on last edited by
                  #11

                  The function for thresholding works extremely fast compared by using SetPixel and GetPixel. However, i got another problem now. My camera (frame grabber) returns the captured image in a CDC object only. And not in a Cbitmap. A CDC object does not have SetBitmapbits and GetBitmapBits members, so i cant call those. I can only access pixels in CDC using GetPixel and SetPixel. (Correct me if i'm wrong). And using Get & SetPixel is too slow, hence i needed a faster algorithm which you came up with. To use getbitmapbits, the object must be a CBItmap. However, my question is now, how to copy contents of a CDC/DC buffer or object (already contains data) to a CBitmap object for processing, and then back to CDC object? //------------custom hardware function that draws image from camera to DC-----------// imgPlot ((GUIHNDL)MemDC.GetSafeHdc(), (void *)ImaqBuffer, 0, 0, Big, Big, 410, 10, plotFlag)); //------------------------------------------- MemDC is a DC. Now contains an image copied from the camera buffer (ImaqBuffer) using a driver function. How to copy MemDC to a CBitmap and do the thresholding with the function you came up with? After finishing, how to copy the CBitmap back to MemDC for plotting on window etc. THanks for the great help. :)

                  J 1 Reply Last reply
                  0
                  • U uus99

                    The function for thresholding works extremely fast compared by using SetPixel and GetPixel. However, i got another problem now. My camera (frame grabber) returns the captured image in a CDC object only. And not in a Cbitmap. A CDC object does not have SetBitmapbits and GetBitmapBits members, so i cant call those. I can only access pixels in CDC using GetPixel and SetPixel. (Correct me if i'm wrong). And using Get & SetPixel is too slow, hence i needed a faster algorithm which you came up with. To use getbitmapbits, the object must be a CBItmap. However, my question is now, how to copy contents of a CDC/DC buffer or object (already contains data) to a CBitmap object for processing, and then back to CDC object? //------------custom hardware function that draws image from camera to DC-----------// imgPlot ((GUIHNDL)MemDC.GetSafeHdc(), (void *)ImaqBuffer, 0, 0, Big, Big, 410, 10, plotFlag)); //------------------------------------------- MemDC is a DC. Now contains an image copied from the camera buffer (ImaqBuffer) using a driver function. How to copy MemDC to a CBitmap and do the thresholding with the function you came up with? After finishing, how to copy the CBitmap back to MemDC for plotting on window etc. THanks for the great help. :)

                    J Offline
                    J Offline
                    J Eric Vaughan
                    wrote on last edited by
                    #12

                    try using MemDC.GetCurrentBitmap() which returns a pointer to a CBitmap. Then you can do the thresholding with it.

                    U 1 Reply Last reply
                    0
                    • J J Eric Vaughan

                      try using MemDC.GetCurrentBitmap() which returns a pointer to a CBitmap. Then you can do the thresholding with it.

                      U Offline
                      U Offline
                      uus99
                      wrote on last edited by
                      #13

                      Thanks, i tried that (GetCurrentBitmap), and it is exactly what i needded. Thanks a lot! You're a genius! Guess it works! Thanks a lot. I'll find u againg, if i've got problem.. haha :P

                      1 Reply Last reply
                      0
                      Reply
                      • Reply as topic
                      Log in to reply
                      • Oldest to Newest
                      • Newest to Oldest
                      • Most Votes


                      • Login

                      • Don't have an account? Register

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • World
                      • Users
                      • Groups