meltingice / CamanJS

Javascript HTML5 (Ca)nvas (Man)ipulation
http://camanjs.com
BSD 3-Clause "New" or "Revised" License
3.56k stars 406 forks source link

Curves on RGB does not work as expected? #112

Open confile opened 11 years ago

confile commented 11 years ago

I have the following image:

buddy is_das_soziale_netzwerk_fr_tierfreunde_und_die_tiere

I tried to apply the following curve:

this.curves('rgb', [0, 0], [55, 43], [94, 226], [255, 255]);

This is the result in Photoshop:

_image_filters psd_bei_34_6 __kurven_1__ebenenmaske_8___-2

This is the Camanjs result:

buddy is_das_soziale_netzwerk_fr_tierfreunde_und_die_tiere-2

What did I wrong?

Here is a working example: http://jsfiddle.net/confile/DTGXn/

confile commented 11 years ago

@meltingice Do you have any idea on this issue?

bebraw commented 11 years ago

@confile I can't repro this with my algo (de Casteljau). Either my implementation is incorrect or there's some other difference. Are you getting the same result in GIMP or some other app? Would it be possible for you to provide a screenshot of Photoshop curve and settings?

bebraw commented 11 years ago

It is as if PS uses some form of curve fitting on those values. Ie. the values are absolute values the curve passes. In the implementation those are just reference points that may not be never reached. You can actually sort of mimic this with a declaration like this:

this.curves('rgb', [0, 0], [54, 43], [55, 43], [56, 44], [93, 226], [94, 226], [95, 226], [255, 255]);

The more "padding" you add, the sharper the curve. The results are quite close as you can see from this screenshot:

screenshot 2013-10-13 20 42 08

confile commented 11 years ago

@bebraw Here is my photoshop curve:

eichhrnchen-walnuss jpg_bei_35_2 __kurven_1__blau_8___

I will test it in Gimp as well.

bebraw commented 11 years ago

@confile Ok. I think that single curve explains a lot. It is indeed using some form of curve fitting. What my, and I guess @meltingice's algo does, is to interpolate between given control points. There's no curve fitting in place. But as I mentioned you can sort of mimic that by adding more control points (possible in my algo).

confile commented 11 years ago

@bebraw Here is the same curve with Gimp:

kurven_und__eichhornchen-walnuss__importiert_-1 0__rgb-farben__1_ebene__1280x1030__gimp-2

I do not see a difference to what Photoshop did.

bebraw commented 11 years ago

Alright. Let's see what @meltingice thinks about curve fitting. I'm not actually sure what it would take algorithm-wise.

confile commented 11 years ago

@bebraw I could not manage to compile toe coffescript on osx can you please update the dist folder in your repo? Thank you.

The fitting you did with the cure is far away from the result it should be.

bebraw commented 11 years ago

@confile The dist of my repo should be up to date. Just remember to look at the right branch (arbitrarycp). You can download the dist version through the web UI.

If you can point me to some curve fitting implementation online (preferably with arbitrary cps), I don't mind having a look.

confile commented 11 years ago

@bebraw Are the points for your curve like in this graph: http://cubic-bezier.com/ I mean are they not on the curve?

confile commented 11 years ago

@bebraw If it is not like in Photoshop or in Gimp that the curve is not very useful, because you cannot use them for anything to compare with a Photoshop or Gimp result. What do you think?

confile commented 11 years ago

@bebraw I tried the branch (arbitrarycp) Using the lomo filter gives this:

buddy is_das_soziale_netzwerk_fr_tierfreunde_und_die_tiere

bebraw commented 11 years ago

@bebraw Are the points for your curve like in this graph: http://cubic-bezier.com/ I mean are they not on the curve?

Exactly. This is how the algorithms work. In my case you can just have an arbitrary amount of control points. It iterates towards the solution (reduces amount of control points to one per t till solved). Bilinear etc. rely on formulas. That makes them nice and fast on low resolution. On high resolution it becomes expensive.

@bebraw If it is not like in Photoshop or in Gimp that the curve is not very useful, because you cannot use them for anything to compare with a Photoshop or Gimp result. What do you think?

It seems PS, GIMP etc. implement actually another variant known as Catmull-Rom spline. As you can see the curves are guaranteed to pass through the control points.

I think we could end up with two variants. The arbitrary one (replaces current implementation) and this. If you need the new behavior, just pass Catmull-Rom generator to curves as an extra parameter. What would that sound @meltingice? This would allow us to retain backwards compatibility and provide an extension point while at it.

confile commented 11 years ago

I think that Catmull-Rom spline should be the default one because they are much more common to users. They probably have used Photoshop or Gimp before so this is common to them.

@bebraw What do you think about the bug I posted in the image above where the surrounding of the image is black?

meltingice commented 11 years ago

I think for now, using a Catmull-Rom spline should be an opt-in option. We can also consider making it the default with the next major release.

bebraw commented 11 years ago

@bebraw I tried the branch (arbitrarycp) Using the lomo filter gives this:

@confile There might be vignette or something in the lomo filter. My work doesn't do any masking.

I would suggest we implement a modified version of Catmull-Rom. That will avoid certain visual artefacts. That Java code there should be relatively easy to port to JS.

I think for now, using a Catmull-Rom spline should be an opt-in option. We can also consider making it the default with the next major release.

What sort of API would you suggest? What if we make it possible to pass a curve generator as an extra argument and default to bezier (backwards compatible). If someone needs Catmull-Rom that can be passed in instead. On 5.0 you could switch to it by default as you suggested.

I can make a separate pull request for this. It might be a good idea to review and merge the current work before that, though.

confile commented 11 years ago

@bebraw modified version of Catmull-Rom would be great. How much time will it cost you to bring it to JS?

bebraw commented 11 years ago

@confile Something like 2-3 hours. I'll try to get this done this week at some point.

confile commented 11 years ago

@bebraw Great if I can do something beside testing let me know.

bebraw commented 11 years ago

@confile Sure!

confile commented 11 years ago

May be this will help you: https://github.com/sporritt/jsBezier

bebraw commented 11 years ago

I found a better source at Unity docs. Need to port that bit of code at the end to CamanJS. Looks pretty straight-forward. Going to give it a go tomorrow.

confile commented 11 years ago

@bebraw great. I am happy to see it.

bebraw commented 11 years ago

@confile I did the initial port. You can see results at jsbin. Note that it renders just the curve itself (flipped y). There is still some glitch with [0, 0]. It has something to do with the way the tangent is calculated although I'm not entirely sure what yet.

Anyway, give it a go and play with the curve to see if you can make it pop in a bad way or something.

confile commented 11 years ago

@bebraw I did not get it. How do I have to set up a curve? Is it this way: [in_1, out_1], [in_2, out_2],...,[in_n, out_n]

confile commented 11 years ago

I tried to model the following curve: var points = [[0, 0], [55, 43], [140, 196], [255, 255]];

This is the original in Photoshop:

screenshot_24 10 13_00_33

your approach gives:

js_bin_-_collaborative_javascript_debugging

confile commented 11 years ago

@bebraw Okay I see that you have to flip the x-axis and then it is close but there is still this edge at the point 140, 196

bebraw commented 11 years ago

@confile Thanks! Looks like the algorithm begins to fail after certain point. I wonder what's going on. Anyway, I'll look into it.

bebraw commented 11 years ago

@confile Another go. I flipped it. There was wrong operation at certain place. Do you think it looks acceptable now? Try some special cases to see if we get knots.

confile commented 11 years ago

@bebraw Great I testet this curve: var points = [[0, 0], [31, 107], [115, 42], [194, 216], [255, 255]];

js_bin_-_collaborative_javascript_debugging

Photoshop:

screenshot_24 10 13_15_16

Look where the arrow is. It does not look so smooth when you compare it to photoshop. By the way good job.

bebraw commented 11 years ago

@confile One more go. I simplified it further. Looks like there's still tiny difference but I'm not sure if it makes any real difference in practice, though.

confile commented 11 years ago

@bebraw Looks great fantastig job of you. I also think that it will not make any difference in practice.

Will you insert this into Caman.js?

bebraw commented 11 years ago

@confile Yup. That's the next step. I'll need to port the code to CoffeeScript and do the necessary tweaks.

As discussed above I'll make it so that you can pass the method to curves as an optional parameter. After that it will use it instead of the default (bezier). In 5.0 @meltingice can default to it if he wants to.

bebraw commented 11 years ago

@confile I suggest you look at #116. ;)