ermig1979 / Simd

C++ image processing and machine learning library with using of SIMD: SSE, AVX, AVX-512, AMX for x86/x64, VMX(Altivec) and VSX(Power7) for PowerPC, NEON for ARM.
http://ermig1979.github.io/Simd
MIT License
2.03k stars 406 forks source link

Bug in SimdResizeMethodNearest resizer #202

Closed mikeversteeg closed 2 years ago

mikeversteeg commented 2 years ago

Calling SimdResizerRunwith SimdResizeMethodNearestgives spill on the right of the resized image. E.g. if I have two YUV420P images of 1920*1080 and copy one to the first quadrant of the other (0, 0, 960, 540), there is spill to the right. See image. This does not happen with SimdResizeMethodAreaor SimdResizeMethodBilinear(did not try others) but (very!) unfortunately they are too slow. SimdLib v4.9.111. Windows 64 image

ermig1979 commented 2 years ago

Hello! I have some questions: 1) Is it a source or result image? 2) Could you give code to illustrate the bug.

mikeversteeg commented 2 years ago
  1. The spill is in the target/result image.
  2. 
    void *rcy, *rcu, *rcv;
    rcy = SimdResizerInit(sr.Width(), sr.Height(), tr.Width(), tr.Height(), 1, SimdResizeChannelByte, SimdResizeMethodNearest);
    if (rcy) {
    SimdResizerRun(rcy, syuv+sr.Left+sr.Top*sw, sw, tyuv+tr.Left+tr.Top*tw, tw);
    SimdRelease(rcy);
    }
    rcu = SimdResizerInit(sr.Width()/2, sr.Height()/2, tr.Width()/2, tr.Height()/2, 1, SimdResizeChannelByte, SimdResizeMethodNearest);
    if (rcu) {
    SimdResizerRun(rcu, syuv+sw*sh + sr.Left/2+sr.Top*sw/2, sw/2, tyuv+tw*th + tr.Left/2+tr.Top/2*tw/2, tw/2);
    SimdRelease(rcu);
    }
    rcv = SimdResizerInit(sr.Width()/2, sr.Height()/2, tr.Width()/2, tr.Height()/2, 1, SimdResizeChannelByte, SimdResizeMethodNearest);
    if (rcv) {
    SimdResizerRun(rcv, syuv+sw*sh*5/4 + sr.Left/2+sr.Top*sw/2, sw/2, tyuv+tw*th*5/4 + tr.Left/2+tr.Top/2*tw/2, tw/2);
    SimdRelease(rcv);
    }
mikeversteeg commented 2 years ago

While you're looking into this.. Do you think even further speed improvement is possible by resizing an YUV frame in 1 pass instead of 3?

ermig1979 commented 2 years ago

I added test ResizeYuv420pSpecialTest() to TestResize.cpp.

./Test -m=s -fi=ResizeYuv420p -w=1920 -h=1080

Source image: src

Output image: dst

Green background value in output image is result of Simd::Fill(yuvDst, 0);

mikeversteeg commented 2 years ago

Note the spill is green so won't show up in this test. Also note it is only with nearest filter, if I replace the filter in my code with e.g. area then the bug is gone.

ermig1979 commented 2 years ago

Can this spill is consequence of using of uninitialized memory in the output or input image?

mikeversteeg commented 2 years ago

No. Do you understand this only happens with SimdResizeMethodNearest? Spill is always beyond target line and green so it will not show up in your test. Maybe it is also exclusive to Windows 64, I cannot confirm.

mikeversteeg commented 2 years ago

I tested again all 4 resize methods ((Nearest, Bilinear, Bicubic, Area) and can confirm only Nearest has this bug. If it's not a bug then maybe I misunderstood the documentation and my code is wrong, but it's remarkable the other 3 methods work flawlessly.

ermig1979 commented 2 years ago

I made my test maximal close to your example (https://github.com/ermig1979/Simd/blob/master/src/Test/TestResize.cpp#L526), but could't reproduce the bug. Could you see at this test and correct me if I did some wrong?

mikeversteeg commented 2 years ago

I have now moved away from Nearest as I noticed in some case Bilinear looks better and it does not use noticeably more CPU. So for me this is no longer relevant, in fact you may drop support for Nearest all together :). Would you still like me to look into this?

ermig1979 commented 2 years ago

I think this very specific bug (if it really exists) so I think is better to close this issue.