0x09 / resdet

Detect source resolution of upscaled images
GNU Lesser General Public License v2.1
234 stars 10 forks source link

Interested in writing a Python port of resdet #5

Closed datumbox closed 5 years ago

datumbox commented 5 years ago

Hello,

I would be interested writing a python port of your method(s); I wonder if you could share more info on how it works. From the readme files I understand you look on the Discrete Cosine Transform of the image for the location of the zero-crossings. Once you find the location of the black lines in both axis, you know the original size of the picture. Is what i mention accurate?

Can you share any other hints on the technical details of the implementation or any other references?

Also could you share any insights on what resampling filters are identifiable by this technique (Bilinear, Bicubic, Nearest, etc)? Thanks!

0x09 commented 5 years ago

Hi @datumbox

If your goal is to expose this functionality to python scripts, the best way to do this is to compile libresdet as a shared library and integrate it with your script using ctypes or CFFI. There isn't currently a target to build a shared version of the library (in part because the API is not 100% stable yet), but I'd be happy to add one if it would help here. libresdet is small and fairly simple to bridge to other languages; I've had good success creating similar bindings for PHP and Ruby.

On the other hand if your goal is to outright replicate resdet's functionality, then the key thing to understand is that after upscaling e.g. horizontally, each row of the DCT spectrum of the resulting image has roughly odd symmetry around the coordinate that was upscaled from. How asymmetrical the row is does depend on the resampling filter used, but all conventional filters exhibit this to some extent. The trick is in striking a balance between finding areas that are mostly symmetrical without so much margin that you get false positives nor too little margin that you get false negatives. While resdet's exact methods for determining this are freely available here in this repo, they are only my attempts at identifying this pattern (not necessarily the best!), so I'd encourage you to try looking for novel solutions to this problem.

Closing this as it's not a code-related issue, however if support for building a shared library would be helpful for creating bindings like mentioned above please do open a new issue for this.

datumbox commented 5 years ago

@0x09 Thanks a lot for the reply. Apologies for opening a ticket, this is indeed not code-related but I just wanted to follow up on your work, say I find it very interesting and ask some questions. :)

My target is to reproduce your approach using the standard numerical libs of Python. I wrote a prototype that follows an approach inspired by yours. How similar/identical it is to yours is unclear to me right now as I don't code in C and I don't yet fully understand your entire codebase. Here is what I do:

  1. I estimate the DCT of the image just like you. Then I take its absolute value and work directly with it.
  2. A 2D-window function is applied separately on x and y axis. This function assesses potential location of the blacklines in DCT.
  3. I tried different methods to find the location of the lines but here is what worked for me best: In the middle of the window function I put the candidate location. Then I check on the left and on the right of this location, how often the candidate line has smaller values than its surroundings column-wise. I do this in a 2d manner for the entire row.
  4. The first candidate that surpasses a given threshold is the most likely candidate.

I think I should be very close to what you do. What I don't fully get in your implementation is why you look for changes in signs. Originally I was under the impression you were working on the absolute values of the DCT. Clearly that can't be the case but I could not spot in your code-base any differentation/derivative function. How similar do you think my approach is to yours? Is it identical only implemented differently or you see material differences?

BTW I did a few limited tests and it seems to work well for various resizing techniques, jpeg compression levels etc. I'll check it out again next weekend as it's really interesting. Thanks a lot for making this open-source and for the cool idea.

0x09 commented 5 years ago

The example image in the README is indeed an absolute value spectrum generated by one of the tools in dspfun for visualization, but this isn't done internally in resdet. Sign is significant since we're looking for odd symmetry around the location of the original image bounds. Here is an artificial example spectrum of a signal that was upsampled from 4 points to 8:

0 1 2 3 4 5 6 7
99 5 -8 2 0 -2 8 -5

We'll never encounter something perfectly symmetrical like this (even less so with more complex filters), but it shows the kind of pattern we're looking for. Checking for opposite signs on either side helps with accuracy, but overall it sounds like you have the right idea. Your current approach is very similar but not identical to any of the current detection methods, so it should be interesting to compare the results.

datumbox commented 5 years ago

Just a heads up. After receiving your clarifications, I implemented your sign method and compared it with mine. My findings show that your method is more resilient to various jpeg compression levels than mine. Thanks for sharing your work. Consider writing a white paper with your findings, it's definitely worth it.