Forum Discussion

SlickRick's avatar
SlickRick
Contributor
2 years ago

Small image detection in a larger image but with undefined position

Hi all,

 

I was wondering if in testcomplete it was possible to detect if a given image is found anywhere in a larger image?

 

The reason for this, is that I have a CAD application where I would like to verify that a certain image/drawing gets added in my 3D model when I define it in the UI. But since the display 3D viewport can change based on the test machine and the size of the viewport, I cannot guarantee the position of the new added element in the 3D.

 

If this is not possible, how would someone achieve this handle this kind of testing? (or maybe it is discourage to test such a thing using Automated UI test?)

 

Thanks!

    • SlickRick's avatar
      SlickRick
      Contributor

      Hi Marsha_R, sadly in my case too many operations that can affect the 3D to change and therefore the test would not be precise enough.

      I understand that what i want to achieve is probably far fetched but still wanted to check if by any change it was possible.

      If not ill try other approaches or leave those kind of test as manual tests. 

      • Marsha_R's avatar
        Marsha_R
        Moderator

        I've come across similar situations in the past where where it was quicker to look at the image/text/etc. in question than it was to code a test to do it. We typically did those tests at the beginning of the test cycle in order to leave time for fixes and then checked again at the end to make sure everything was still ok. 

  • If the CAD application can print an area of the overall view, then you can simply print images before and after your changes of that location and compare them. If it can only print the full image, then you can use this method to search for a bitmap image in a larger, or same size, source image. 

     

    It’s complied from several sources, which I can no longer remember…it’s been about 15 years.  I used it as part of an automated testing software that I created, so I know it works well and is very fast. 

     

    It is a static method, and the images need to be bitmaps. There are lots of libraries that can convert PDFs to images, if images are not an option from your CAD package. It will return the location, in pixels, of the smaller image within the larger image as a rectangle.  If the image is not found it will return a rectangle with x, y, width and height with zero values.  The returned rectangle can be used to highlight the location in the source image, if needed.  Of course, it can be modified to just return a Boolean true/false.  I hope this helps.  

     

    This can be complied into a DLL file and used through the DotNet libraires of TestComplete.

     

     

      public void Test()
      {
          System.Drawing.Bitmap source = (System.Drawing.Bitmap)System.Drawing.Image.FromFile(@"C:\Source.bmp");
    
          System.Drawing.Bitmap bmp = (System.Drawing.Bitmap)System.Drawing.Image.FromFile(@"C:\Search2.bmp");
    
          Rectangle r = source.InImage(bmp);
      }
    
      public static Rectangle InImage(this System.Drawing.Bitmap src, System.Drawing.Bitmap bmp)
      {
          Rectangle result = default;
          
          if (src== null || bmp == null || bmp.Width > src.Width || bmp.Height > src.Height)
              return result;
    
          src=(System.Drawing.Bitmap)src.Clone();
          bmp = (System.Drawing.Bitmap)bmp.Clone();
    
          Rectangle sr = new Rectangle(0, 0, src.Width, src.Height);
          Rectangle br = new Rectangle(0, 0, bmp.Width, bmp.Height);
          BitmapData srcLock = src.LockBits(sr, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
          BitmapData bmpLock = bmp.LockBits(br, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
          int sStride = srcLock.Stride;
          int bStride = bmpLock.Stride;
    
          checked
          {
              int srcSz = sStride * src.Height;
              int bmpSz = bStride * bmp.Height;
              byte[] srcBuff = new byte[srcSz + 1];
              byte[] bmpBuff = new byte[bmpSz + 1];
              System.Runtime.InteropServices.Marshal.Copy(srcLock.Scan0, srcBuff, 0, srcSz);
              System.Runtime.InteropServices.Marshal.Copy(bmpLock.Scan0, bmpBuff, 0, bmpSz);
              bmp.UnlockBits(bmpLock);
              src.UnlockBits(srcLock);
              int bw = bmp.Width;
              int bh = bmp.Height;
              int sw = src.Width - bw;
              int sh = src.Height - bh;
              int bx;
              int by;
              int num = sh;
              for (int y = 0; y <= num; y++)
              {
                  int sy = y * sStride;
                  int num2 = sw;
                  for (int x = 0; x <= num2; x++)
                  {
                      int sx = sy + x * 3;
                      byte r = srcBuff[sx + 2];
                      byte g = srcBuff[sx + 1];
                      byte b = srcBuff[sx];
                      if (r == bmpBuff[2] && g == bmpBuff[1] && b == bmpBuff[0])
                      {
                          result = new Rectangle(x, y, bmp.Width, bmp.Height);
                          int num3 = bh - 1;
                          for (int y2 = 0; y2 <= num3; y2++)
                          {
                              by = y2 * bStride;
                              int num4 = bw - 1;
                              for (int x2 = 0; x2 <= num4; x2++)
                              {
                                  bx = by + x2 * 3;
                                  sy = (y + y2) * sStride;
                                  sx = sy + (x + x2) * 3;
                                  r = srcBuff[sx + 2];
                                  g = srcBuff[sx + 1];
                                  b = srcBuff[sx];
                                  if (r != bmpBuff[bx + 2] || g != bmpBuff[bx + 1] || b != bmpBuff[bx])
                                  {
                                      result = default;
                                      sy = y * sStride;
                                      break;
                                  }
                              }
                              if (result == default)
                                  break;
                          }
                      }
                      if (result != default)
                          break;
                  }
                  if (result != default)
                      break;
              }
              return result;
          }
      }