libvips / lua-vips

Lua binding for the libvips image processing library
MIT License
125 stars 10 forks source link

"pngload: out of order" #53

Closed Corotyest closed 1 year ago

Corotyest commented 1 year ago

Hello, good evening. I was testing a system of "searching" an image within one, and I am sorry if this is easy to solve, however, I have a speculation although I do not know exactly how to carry it out. My idea about this problem is that I'm cutting out an image before, but isn't Lua supposed to wait until the process is finished?

The code in question:

local function searchImg(img, tar, s)
    local cordX, cordY = search(img, tar, s) -- the "real" searcher, nothing to show

    local sizeX, sizeY = tar:size()
    local radX, radY = sizeX/2, sizeY/2

    -- s = s and s>1 and (s-1) or (s or 0)
    local left, top = cordX-radX, cordY-radY
    local image = img:crop(left, top, sizeX, sizeY)

    if image:equal(tar):min() == 255 then
        return {
            top = top,
            left = left,
            width = sizeX,
            height = sizeY
        }, image
    end

    return nil
end

Output: image

Corotyest commented 1 year ago

I also noticed that apparently before doing the operation if I try to make 'tar' be written as ".png" I get this error: image

Corotyest commented 1 year ago

Now I've got this other error. image

Corotyest commented 1 year ago

I had commented the line where I crop the image that I want to compare so I can secure it match the one of search. And if someone ask also with .jpg files it throw the same error. image

jcupitt commented 1 year ago

Hi @Corotyest,

I guess you are opening the image in sequential mode. You need plain new_from_file (no options) to get random access mode.

There are a million ways to search for a subimage. Cross correlation is probably the best:

https://en.wikipedia.org/wiki/Cross-correlation

tldr: take the fft of both images, multiply them, the position of the peak in the result is the position of the subimage.

You can also extract a small part of the subimage, do a convolution against the big image, and search for peaks. Each peak is a candidate for the position of the subimage.

If you pick a couple of high-contrast areas from the subimage (eg. five distinctive 16x16 patches selected from across the subimage) and search for matches for all of them, then the point where all five show up in one place is almost certainly the position of the subimage.

For very large images, you probably need to downsample first to get an approximate position, then search again on the full res data.

Picking an appropriate algorithm depends on your CPU, memory, time and accuracy requirements (as always in engineering!).

jcupitt commented 1 year ago

... please don't post screenshots. I can't copy-paste from them, so it makes it hard for me to reproduce any results you get.

Instead, copy-paste the text itself and put it in triple backquotes, with the formatting style you want, for example:

```lua
function fwrite (fmt, ...)
  return io.write(string.format(fmt, unpack(arg)))
end
```

Is displayed by github as:

    function fwrite (fmt, ...)
      return io.write(string.format(fmt, unpack(arg)))
    end

Leave off the formatting name if you want plain text like a terminal session:

```
john@banana ~/GIT/libdicom/src (add-vr-enum) $ grep set_value_str_multi *
dicom-data.c:    if (!set_value_str_multi(element, values, 1, capacity)) {
dicom-data.c:    if (!set_value_str_multi(element, values, vm, capacity)) {
john@banana ~/GIT/libdicom/src (add-vr-enum) $ 
```

To display:

john@banana ~/GIT/libdicom/src (add-vr-enum) $ grep set_value_str_multi *
dicom-data.c:    if (!set_value_str_multi(element, values, 1, capacity)) {
dicom-data.c:    if (!set_value_str_multi(element, values, vm, capacity)) {
john@banana ~/GIT/libdicom/src (add-vr-enum) $ 
jcupitt commented 1 year ago

Ooop, I see you know about the quoting, heh.

Corotyest commented 1 year ago

First of all, thanks for the answer. I wasn't really sure whether to post this here. About the following:

I guess you are opening the image in sequential mode. You need plain new_from_file (no options) to get random access mode.

Doing more rigorous tests I realized (together with a colleague) that the problem is due to the fact that the image used as the second argument, that is, tar, is of type thumbnail like

vips.Image.thumbnail(name)

however; if I open the image as VipsImage:thumbnail_image() this no longer invokes an error.

Corotyest commented 1 year ago

And also thank you very much for the suggestion as if I am somewhat new to this is such an amazing (arguably) library.

Sorry about my mistake, Those were console errors that I thought it appropriate to send as an image, but I will also take that recommendation very seriously.

jcupitt commented 1 year ago

Ah OK. Yes, thumbnail always makes a sequential image, you can't do random access from it.

I wouldn't use thumbnail_image (it's only there for emergencies), instead do:

local image = vips.Image.thumbnail("something.jpg", 512):copy_memory()

That'll make a quick thumbnail, then render it into memory. Now references to image will fetch pixels from the memory area, so random access will work.

I tweaked the main README to stress that thumbnail is only for fast thumbnail generation, not general purpose image loading.

Corotyest commented 1 year ago

Sorry for the late response. Where we can talk most often about questions? And thanks for your help.

Corotyest commented 1 year ago

https://en.wikipedia.org/wiki/Cross-correlation

tldr: take the fft of both images, multiply them, the position of the peak in the result is the position of the subimage.

You can also extract a small part of the subimage, do a convolution against the big image, and search for peaks. Each peak is a candidate for the position of the subimage.

And could you give me an example about doing this, how you would do that? Thanks and good afternoon, Corotyest.