0

I have many PNG screenshots with an identical piece of graphic in each of them. The piece has the same dimensions in all of the images.

What command line program can I use to find the position of it in each of the files (fed to one by one)?

5
  • What format are screenshots in? Commented Sep 19, 2015 at 20:19
  • @MatthewRock .png Commented Sep 19, 2015 at 20:19
  • Why do you need these? I'm afraid it's not that tirvial. Commented Sep 19, 2015 at 21:07
  • So the sub-image you want can change position? It's not always at the same coordinates within the image? You should look into image processing software. I very much doubt this is something you'll be able to do with a single commandline. Commented Sep 19, 2015 at 22:19
  • I'm not aware of any standard program that does this out of the box, however the OpenCV library provides a matchTemplate correlation-based object detector. There's a C++ demo but you should also be able to use the Python API. If scaling or rotation are required, then it's less straightforward. Commented Sep 19, 2015 at 22:19

1 Answer 1

-1

The following is only a rough idea, no ready solution (especially no code!).

I would convert a sample of the small graphic and the screenshots to a raw (uncompressed) format (TGA has abolultely no compression, it's just a complete dump of every pixel) and then grep for the graphic in the screenshot file. Then calculate the position.

For the calculation you need the dimensions (width and height) of the images which you can get with Image Magick's identify command. That is:

GRAPHIC_WIDTH=$(identify -verbose graphic.tga | sed -n '/Geometry:/s%.*Geometry:\ \(.*\)x.*%\1%p') GRAPHIC_HEIGHT=$(identify -verbose graphic.tga | sed -n '/Geometry:/s%.*x\([^+]*\)+.*%\1%p') 

The first 18 bytes of a TGA file do not contain pixel information, so should be omitted:

tail -c +19 graphic.tga > graphic.colorinfo 

And, as in the comments from MatthewRock, you can’t grep for the whole graphic at once because it is saved line by line and surrounded by pixels from the screenshot, you should search linewise, i.e. search for the first pixel line of the graphic, and if that was found then search for the second line X pixels further, where X is the width of the screenshot minus the width of the graphic.

You should use grep with the option -F and a graphic file separated by new lines at K pixels, where K is the width of the graphic times its color depth in bytes. Do this with head and tail. If the colordepth is 8 bits then every pixel line is K bytes long, if the colordepth is higher, e.g. 24 bits or 3 bytes, the pixel line is K times 3 bytes long, etc.:

The 10th line that is 20 pixels long and has a colordepth of 3 bytes could be obtained in the following way:

head -c $((10*20*3)) graphic.colorinfo | tail -c 60 

Of course there are cases where this approach would be somewhat complicated to write with shell code, e.g. if the screenshot is completely unicolored white (and the graphic, too), and the graphic only has one black pixel.

The idea is to save temporary start coordinates (position of left most and top most pixel where the first line matches) and from there search the lines below until one line does not match, then start from the next matching first line, etc.

Finally I have to say that it would be much easier to do it on a byte level (not work on images with text tools), such as a hexeditor. Or even better use C or python. But the approach would be the same (searching for matching lines).

7
  • How do you grep for the graphic ??? Commented Sep 19, 2015 at 22:46
  • Well, you could use the output of cat graphic as search string and a screenshot at a time as file to use the grep command on. If that doesn't work, then base64 convert the files first. Example: grep $(cat graphic.bmp) scrennshot1.bmp or: grep $(base64 graphic.bmp) <(base64 screenshot1.bmp) Commented Sep 19, 2015 at 22:49
  • But these are laid out like: noise - tiny part of window - noise - eol - noise - tiny part of window-2 - noise - eol ... etc. How do you imagine searching for that? Commented Sep 19, 2015 at 22:52
  • Well, you are right. Then just search for the first pixel line of the graphic. And if that was found then search for the second line X pixels further, where X is the width of the screenshot minus the width of the graphic. Etc., to be elaborated. This is only a rough idea. It is possible to do it this way and shouldn't be to slow. Later it could be translated into C code. Commented Sep 19, 2015 at 22:57
  • 1
    Please edit your answer and include the specific suggestions from the comments. Especially how to make the transformations you suggest. Commented Sep 19, 2015 at 23:30

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.