Skip to content

Instantly share code, notes, and snippets.

@mcanthony
Forked from rogerbraun/README.md
Created October 21, 2015 01:31
Show Gist options
  • Save mcanthony/9c1745f4eb122a7dea8c to your computer and use it in GitHub Desktop.
Save mcanthony/9c1745f4eb122a7dea8c to your computer and use it in GitHub Desktop.

Revisions

  1. rogerbraun revised this gist Sep 19, 2011. 1 changed file with 15 additions and 11 deletions.
    26 changes: 15 additions & 11 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -1,34 +1,38 @@
    # How to get the selective color effect

    When I started to program for this Codebrawl, I had essentially two ideas how to do this: Try to detect each crayon as an object and keep one of them in color, or take a reference color and just keep the colors that are similar to it. The first idea would be more universal, but seems to me much harder to implement. I chose the second one, so I needed a way to measure the distance between to colors.
    When I started thinking about this Codebrawl, I had essentially two ideas how to do get the selective color effect: Try to detect each crayon as an object and keep one of them in color, or take a reference color and just keep the colors that are similar to it. The first idea would be more universal, but seems to me much harder to implement. I chose the second one, so I needed a way to measure the distance between to colors.

    ## How to measure the distance between colors

    There are several ways to get a value that tells you how much colors are like each other. If you have an RGB pixel, you could just take these 3 values as coordinates in a three dimensional space and calculate the distance there. I did not actually implement this, as it does not represent similar colors in the way we would see them. For example, the color (255,0,0) and (127,0,0) would both be just red, but they would have the same distance as (255, 128, 0), which intruduces green to the color and looks pretty different.
    There are several ways to get a value that tells you how much colors are like each other. If you have an RGB pixel, you could just take these 3 values as coordinates in a 3D space and calculate the distance there. I did not actually implement this, as it does not represent similar colors in the way we would see them. For example, the color (255,0,0) and (127,0,0) would both be just red, but they would have the same distance as (255, 128, 0), which introduces green to the color mix and looks pretty different.

    This also tells us something about what kind of representation we want: One where only the color counts, but not the brightness (or luminance). I first looked at rg chromaticty space.
    This also tells us something about what kind of representation we want: One where only the color counts, but not the brightness (or luminance). I first looked at a color representation called rg chromaticty space.

    ### rg chromacity

    rg chromacity is a simple way to remove intensity information from your colors and only keep the proportions of red, green and blue. What you do is just normalize the values to be between 0 and 1, with r + g + b always adding up to one. It is called rg chromacity because only the red and green components are needed to describe a color, as the blue component is always b = 1 - (r + g). For example, rgb(255,0,0) is rg(1,0), as is rgb(200,0,0).
    rg chromacity is a simple way to remove intensity information from your colors and only keep the proportions of red, green and blue. You just normalize the values of the r, g and b components to be between 0 and 1, with r + g + b always adding up to one. It is called rg chromacity because only the red and green components are needed to describe a color, as the blue component is always b = 1 - (r + g). For example, rgb(255,0,0) is rg(1,0), as is rgb(200,0,0).

    You now have a 2d space, so distances can be easily calculated. This gives somewhat satisfactory results, at least for some of the crayons. But in the end, it just was not as good as I had hoped. Part of this surely is the how this color space actually looks. It is somewhat uneven, as the distance between pure red, rg(1,0) and pure blue, rg(0,0) is one. But between red and green, rg(0,1), it is the square root of two! By just measuring the distance, I am essentially cutting a circle of colors I want to keep, but colors in this space are not uniformly distributed.
    You now have a 2d space, so distances can be easily calculated. This gives somewhat satisfactory results, at least for some of the crayons. But in the end, it just was not as good as I had hoped.

    I had a lot of ideas how to counter these problems: Make colors spread from a reference color if the neighbor are similar, make negative cuts in this space by specifying colors that should be always made gray, etc...
    Part of this surely is grounded in how this color space actually looks. It is somewhat uneven, as the distance between pure red, rg(1,0) and pure blue, rg(0,0) is one. But between red and green,rg(1,0) and rg(0,1), it is the square root of two! By just measuring the distance, I am essentially cutting a circle of colors I want to keep, but similar colors in this space are not uniformly distributed.

    What I really needed was a better distance function for my colors.
    I had a lot of ideas how to counter these problems: Make colors spread from a reference color if the neighbor are similar, make negative cuts in this space by specifying colors that should always be made gray, etc...

    What I really needed was a better distance function for my colors. Let's look at HSV.

    ### HSV

    If you look at color space, you will find HSL and HSV pretty soon. They each use the hue, saturation and lightness or value to define a color. If you take a look at some pictures of this color space, you will quickly see that the hue component looks pretty much like what we need.
    If you look at color spaces on Wikipedia, you will find HSL and HSV pretty soon. They each use the hue, saturation, and lightness or value to define a color. If you take a look at some pictures of this color space, you will quickly see that the hue component looks pretty much like what we need.

    Now, calculating the hue is more complicated than calculating rg chromacity colors. If I understood it correctly, you make a hexagon, put red at 0°, green at 120° and blue at 240° and then calculate where your color lies. You can see the formula I used in the code.
    Now, calculating the hue is more complicated than calculating rg chromacity colors. If I understood it correctly, you make a hexagon, put red at 0°, green at 120° and blue at 240° and then calculate where your color lies. You can see the formula I used in the code. I did move the result around by a few degrees so pure red will be zero. I probably have a bug somewhere, but even if I would not correct it, it does not matter where red, green and blue lie exactly, as long as they have the right distance from each other.

    Calculating the distance is just subtracting one hue from the other. We have to do it two times, though, as hue is circular and has red on both ends. This gives good results for most colors. I could not get the yellow and red crayon to seperate perfectly... This may be because I did not find a good reference color, or just that the dark yellow in the tip of the crayon and the light red are actually too similar and this approach won't work at all. If other entries managed to get a perfect red crayon with no yellow using just the hue, you know which one it is ;-)
    Calculating the distance is just subtracting one hue from the other. We have to do it two times, calculating the modular distance, as hue is circular and has red on both ends. This gives good results for most colors. I could not get the yellow and red crayon to seperate perfectly... This may be because I did not find a good reference color, or just that the dark yellow in the tip of the crayon and the light red are actually too similar and this approach won't work at all. If other entries managed to get a perfect red crayon with no yellow using just the hue, you know which one it is ;-)

    ## Better color distances

    There is a standard for measuring color difference by the International Commission on Illumination (sounds good, right?). It takes into account how humans perceive color, so it should give you the best results (if you are human, that is). I did not try it, though, as it seems somewhat complicated and I wanted to keep this entry short and to the point. Maybe you want to take a shot?
    I tackled the problem of color similarity from a rather primitive point of view: Numerical values of single pixels. As it turns out, this is not enough to mirror human color perception. Take a look at this: http://gizmodo.com/5839481/the-most-wicked-optical-illusion-ive-seen-so-far. Both spirals have the same color, but you would never think that if you didn't know or check. As far as I know, no algorithm that works for cases like this exists, yet.

    There is a standard for measuring color difference by the International Commission on Illumination (sounds good, right?), that takes into account how humans perceive color, so it should give you better results - if you are human, that is. I did not try it, though, as it seems somewhat complicated and I wanted to keep this entry short and to the point. Maybe you want to take a shot?

    ## BONUS: Javascript version

  2. rogerbraun revised this gist Sep 18, 2011. 1 changed file with 5 additions and 5 deletions.
    10 changes: 5 additions & 5 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -2,13 +2,13 @@

    When I started to program for this Codebrawl, I had essentially two ideas how to do this: Try to detect each crayon as an object and keep one of them in color, or take a reference color and just keep the colors that are similar to it. The first idea would be more universal, but seems to me much harder to implement. I chose the second one, so I needed a way to measure the distance between to colors.

    # How to measure the distance between colors
    ## How to measure the distance between colors

    There are several ways to get a value that tells you how much colors are like each other. If you have an RGB pixel, you could just take these 3 values as coordinates in a three dimensional space and calculate the distance there. I did not actually implement this, as it does not represent similar colors in the way we would see them. For example, the color (255,0,0) and (127,0,0) would both be just red, but they would have the same distance as (255, 128, 0), which intruduces green to the color and looks pretty different.

    This also tells us something about what kind of representation we want: One where only the color counts, but not the brightness (or luminance). I first looked at rg chromaticty space.

    ## rg chromacity
    ### rg chromacity

    rg chromacity is a simple way to remove intensity information from your colors and only keep the proportions of red, green and blue. What you do is just normalize the values to be between 0 and 1, with r + g + b always adding up to one. It is called rg chromacity because only the red and green components are needed to describe a color, as the blue component is always b = 1 - (r + g). For example, rgb(255,0,0) is rg(1,0), as is rgb(200,0,0).

    @@ -18,19 +18,19 @@ I had a lot of ideas how to counter these problems: Make colors spread from a re

    What I really needed was a better distance function for my colors.

    # HSV
    ### HSV

    If you look at color space, you will find HSL and HSV pretty soon. They each use the hue, saturation and lightness or value to define a color. If you take a look at some pictures of this color space, you will quickly see that the hue component looks pretty much like what we need.

    Now, calculating the hue is more complicated than calculating rg chromacity colors. If I understood it correctly, you make a hexagon, put red at 0°, green at 120° and blue at 240° and then calculate where your color lies. You can see the formula I used in the code.

    Calculating the distance is just subtracting one hue from the other. We have to do it two times, though, as hue is circular and has red on both ends. This gives good results for most colors. I could not get the yellow and red crayon to seperate perfectly... This may be because I did not find a good reference color, or just that the dark yellow in the tip of the crayon and the light red are actually too similar and this approach won't work at all. If other entries managed to get a perfect red crayon with no yellow using just the hue, you know which one it is ;-)

    # Better color distances
    ## Better color distances

    There is a standard for measuring color difference by the International Commission on Illumination (sounds good, right?). It takes into account how humans perceive color, so it should give you the best results (if you are human, that is). I did not try it, though, as it seems somewhat complicated and I wanted to keep this entry short and to the point. Maybe you want to take a shot?

    # BONUS: Javascript version
    ## BONUS: Javascript version

    I also wrote a javascript version of the same algorithm which you can use to quickly check the effects of changing the reference color or the color distance. You can find it at http://severe-autumn-9391.heroku.com/index.html.

  3. Roger Braun revised this gist Sep 15, 2011. 3 changed files with 44 additions and 2 deletions.
    37 changes: 37 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,37 @@
    # How to get the selective color effect

    When I started to program for this Codebrawl, I had essentially two ideas how to do this: Try to detect each crayon as an object and keep one of them in color, or take a reference color and just keep the colors that are similar to it. The first idea would be more universal, but seems to me much harder to implement. I chose the second one, so I needed a way to measure the distance between to colors.

    # How to measure the distance between colors

    There are several ways to get a value that tells you how much colors are like each other. If you have an RGB pixel, you could just take these 3 values as coordinates in a three dimensional space and calculate the distance there. I did not actually implement this, as it does not represent similar colors in the way we would see them. For example, the color (255,0,0) and (127,0,0) would both be just red, but they would have the same distance as (255, 128, 0), which intruduces green to the color and looks pretty different.

    This also tells us something about what kind of representation we want: One where only the color counts, but not the brightness (or luminance). I first looked at rg chromaticty space.

    ## rg chromacity

    rg chromacity is a simple way to remove intensity information from your colors and only keep the proportions of red, green and blue. What you do is just normalize the values to be between 0 and 1, with r + g + b always adding up to one. It is called rg chromacity because only the red and green components are needed to describe a color, as the blue component is always b = 1 - (r + g). For example, rgb(255,0,0) is rg(1,0), as is rgb(200,0,0).

    You now have a 2d space, so distances can be easily calculated. This gives somewhat satisfactory results, at least for some of the crayons. But in the end, it just was not as good as I had hoped. Part of this surely is the how this color space actually looks. It is somewhat uneven, as the distance between pure red, rg(1,0) and pure blue, rg(0,0) is one. But between red and green, rg(0,1), it is the square root of two! By just measuring the distance, I am essentially cutting a circle of colors I want to keep, but colors in this space are not uniformly distributed.

    I had a lot of ideas how to counter these problems: Make colors spread from a reference color if the neighbor are similar, make negative cuts in this space by specifying colors that should be always made gray, etc...

    What I really needed was a better distance function for my colors.

    # HSV

    If you look at color space, you will find HSL and HSV pretty soon. They each use the hue, saturation and lightness or value to define a color. If you take a look at some pictures of this color space, you will quickly see that the hue component looks pretty much like what we need.

    Now, calculating the hue is more complicated than calculating rg chromacity colors. If I understood it correctly, you make a hexagon, put red at 0°, green at 120° and blue at 240° and then calculate where your color lies. You can see the formula I used in the code.

    Calculating the distance is just subtracting one hue from the other. We have to do it two times, though, as hue is circular and has red on both ends. This gives good results for most colors. I could not get the yellow and red crayon to seperate perfectly... This may be because I did not find a good reference color, or just that the dark yellow in the tip of the crayon and the light red are actually too similar and this approach won't work at all. If other entries managed to get a perfect red crayon with no yellow using just the hue, you know which one it is ;-)

    # Better color distances

    There is a standard for measuring color difference by the International Commission on Illumination (sounds good, right?). It takes into account how humans perceive color, so it should give you the best results (if you are human, that is). I did not try it, though, as it seems somewhat complicated and I wanted to keep this entry short and to the point. Maybe you want to take a shot?

    # BONUS: Javascript version

    I also wrote a javascript version of the same algorithm which you can use to quickly check the effects of changing the reference color or the color distance. You can find it at http://severe-autumn-9391.heroku.com/index.html.

    Use the slider to set the color distance that will still be colored, and just click on any point in the image on the right to set it as reference. Have fun!
    4 changes: 4 additions & 0 deletions extensions.rb
    Original file line number Diff line number Diff line change
    @@ -1,17 +1,21 @@
    module ChunkyPNG::Color
    # See http://en.wikipedia.org/wiki/Hue#Computing_hue_from_RGB
    def self.hue(pixel)
    r, g, b = r(pixel), g(pixel), b(pixel)
    return 0 if r == b and b == g
    ((180 / Math::PI * Math.atan2((2 * r) - g - b, Math.sqrt(3) * (g - b))) - 90) % 360
    end

    # The modular distance, as the hue is circular
    def self.distance(pixel, poxel)
    hue_pixel, hue_poxel = hue(pixel), hue(poxel)
    [(hue_pixel - hue_poxel) % 360, (hue_poxel - hue_pixel) % 360].min
    end
    end

    module SelectiveColor
    # Really simple, just change the pixels to grayscale if their distance to a
    # reference hue is larger than a delta value.
    def to_selective_color!(reference, delta)
    pixels.map!{|pixel| ChunkyPNG::Color.distance(pixel, reference) > delta ? ChunkyPNG::Color.to_grayscale(pixel) : pixel}
    self
    5 changes: 3 additions & 2 deletions selective_color.rb
    Original file line number Diff line number Diff line change
    @@ -5,8 +5,9 @@

    image.extend(SelectiveColor)

    #keep = ChunkyPNG::Color.rgb(221,57,42)
    #keep = ChunkyPNG::Color.rgb(152,216,56)
    # Try the other colors if you like!
    # keep = ChunkyPNG::Color.rgb(221,57,42)
    # keep = ChunkyPNG::Color.rgb(152,216,56)
    keep = ChunkyPNG::Color.rgb(0,125,209)

    image.to_selective_color!(keep, 15)
  4. Roger Braun revised this gist Sep 14, 2011. 1 changed file with 0 additions and 0 deletions.
    Binary file removed input.png
    Binary file not shown.
  5. Roger Braun revised this gist Sep 14, 2011. 1 changed file with 3 additions and 2 deletions.
    5 changes: 3 additions & 2 deletions extensions.rb
    Original file line number Diff line number Diff line change
    @@ -2,11 +2,12 @@ module ChunkyPNG::Color
    def self.hue(pixel)
    r, g, b = r(pixel), g(pixel), b(pixel)
    return 0 if r == b and b == g
    180 / Math::PI * Math.atan2((2 * r) - g -b, Math.sqrt(3) * (g - b))
    ((180 / Math::PI * Math.atan2((2 * r) - g - b, Math.sqrt(3) * (g - b))) - 90) % 360
    end

    def self.distance(pixel, poxel)
    (hue(pixel) - hue(poxel)).abs
    hue_pixel, hue_poxel = hue(pixel), hue(poxel)
    [(hue_pixel - hue_poxel) % 360, (hue_poxel - hue_pixel) % 360].min
    end
    end

  6. Roger Braun revised this gist Sep 14, 2011. 3 changed files with 9 additions and 67 deletions.
    63 changes: 4 additions & 59 deletions extensions.rb
    Original file line number Diff line number Diff line change
    @@ -1,73 +1,18 @@
    module ChunkyPNG::Color
    def self.to_rg(pixel)
    r, g, b = r(pixel), g(pixel), b(pixel)
    [r / (r + g + b).to_f, g / (r + b + g).to_f]
    end

    def self.hue(pixel)
    r, g, b = r(pixel), g(pixel), b(pixel)
    return 0 if r == b and b == g
    180 / Math::PI * Math.atan2(2 * r - g -b, Math.sqrt(3) * (g - b))
    180 / Math::PI * Math.atan2((2 * r) - g -b, Math.sqrt(3) * (g - b))
    end

    def self.distance(pixel, poxel)
    # x, y = to_rg(pixel), to_rg(poxel)
    #a, b = x[0] - y[0], x[1] - y[1]

    # Divide by 1.41 to get results from 0 to 1
    #Math.sqrt((a * a) + (b * b)) / Math.sqrt(2)
    (hue(pixel) - hue(poxel)).abs
    end
    end

    module Neighbors
    def neighbors(x, y = nil)
    unless y
    y = x / width
    x = x - y * width
    end
    candidates = ((x - 1)..(x + 1)).to_a.product(((y - 1)..(y + 1)).to_a)
    candidates.select{|el| include_point? el} - [[x, y]]
    end
    end

    module SelectiveColor
    def to_selective_color(color, avoid = nil, spread = nil)
    colored = pixels.map do |pixel|
    too_far = color.inject(false){|r, (c, d)| r or (ChunkyPNG::Color.distance(c, pixel) > d)}
    too_close = avoid && avoid.inject(false){|r, (c, d)| r or (ChunkyPNG::Color.distance(c, pixel) < d)}
    if too_far or too_close
    false
    else
    true
    end
    end

    if spread then
    modified = true
    while modified do
    modified = false
    pixels.each_with_index do |pixel, i|
    if colored[i]
    neighbors(i).each do |(x,y)|
    unless colored[x + (y * width)]
    other_pixel = get_pixel(x, y)
    if ChunkyPNG::Color.distance(pixel, other_pixel) < spread
    modified = (modified || 0) + 1
    colored[x + (y * width)] = true
    end
    end
    end
    end
    end
    puts "Modified #{modified} pixels"
    end
    end

    colored.each_with_index do |color, i|
    pixels[i] = ChunkyPNG::Color.to_grayscale(pixels[i]) unless color
    end

    return self
    def to_selective_color!(reference, delta)
    pixels.map!{|pixel| ChunkyPNG::Color.distance(pixel, reference) > delta ? ChunkyPNG::Color.to_grayscale(pixel) : pixel}
    self
    end
    end
    Binary file modified output.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
    13 changes: 5 additions & 8 deletions selective_color.rb
    Original file line number Diff line number Diff line change
    @@ -1,17 +1,14 @@
    require "chunky_png"
    require "./extensions.rb"
    require "pry"


    image = ChunkyPNG::Image.from_file("input.png")

    image.extend(SelectiveColor, Neighbors)


    keep = [[ChunkyPNG::Color.rgb(221,57,42), 10]]#[[ChunkyPNG::Color.rgb(152,216,56), 0.1]]
    image.extend(SelectiveColor)

    avoid = nil #[[ChunkyPNG::Color.rgb(255,229,62), 0.05]]
    #keep = ChunkyPNG::Color.rgb(221,57,42)
    #keep = ChunkyPNG::Color.rgb(152,216,56)
    keep = ChunkyPNG::Color.rgb(0,125,209)

    image.to_selective_color(keep)
    image.to_selective_color!(keep, 15)

    image.save("output.png")
  7. Roger Braun revised this gist Sep 14, 2011. 3 changed files with 79 additions and 34 deletions.
    73 changes: 73 additions & 0 deletions extensions.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,73 @@
    module ChunkyPNG::Color
    def self.to_rg(pixel)
    r, g, b = r(pixel), g(pixel), b(pixel)
    [r / (r + g + b).to_f, g / (r + b + g).to_f]
    end

    def self.hue(pixel)
    r, g, b = r(pixel), g(pixel), b(pixel)
    return 0 if r == b and b == g
    180 / Math::PI * Math.atan2(2 * r - g -b, Math.sqrt(3) * (g - b))
    end

    def self.distance(pixel, poxel)
    # x, y = to_rg(pixel), to_rg(poxel)
    #a, b = x[0] - y[0], x[1] - y[1]

    # Divide by 1.41 to get results from 0 to 1
    #Math.sqrt((a * a) + (b * b)) / Math.sqrt(2)
    (hue(pixel) - hue(poxel)).abs
    end
    end

    module Neighbors
    def neighbors(x, y = nil)
    unless y
    y = x / width
    x = x - y * width
    end
    candidates = ((x - 1)..(x + 1)).to_a.product(((y - 1)..(y + 1)).to_a)
    candidates.select{|el| include_point? el} - [[x, y]]
    end
    end

    module SelectiveColor
    def to_selective_color(color, avoid = nil, spread = nil)
    colored = pixels.map do |pixel|
    too_far = color.inject(false){|r, (c, d)| r or (ChunkyPNG::Color.distance(c, pixel) > d)}
    too_close = avoid && avoid.inject(false){|r, (c, d)| r or (ChunkyPNG::Color.distance(c, pixel) < d)}
    if too_far or too_close
    false
    else
    true
    end
    end

    if spread then
    modified = true
    while modified do
    modified = false
    pixels.each_with_index do |pixel, i|
    if colored[i]
    neighbors(i).each do |(x,y)|
    unless colored[x + (y * width)]
    other_pixel = get_pixel(x, y)
    if ChunkyPNG::Color.distance(pixel, other_pixel) < spread
    modified = (modified || 0) + 1
    colored[x + (y * width)] = true
    end
    end
    end
    end
    end
    puts "Modified #{modified} pixels"
    end
    end

    colored.each_with_index do |color, i|
    pixels[i] = ChunkyPNG::Color.to_grayscale(pixels[i]) unless color
    end

    return self
    end
    end
    Binary file modified output.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
    40 changes: 6 additions & 34 deletions selective_color.rb
    Original file line number Diff line number Diff line change
    @@ -1,45 +1,17 @@
    require "chunky_png"
    require "./extensions.rb"
    require "pry"

    module ChunkyPNG::Color
    def self.to_rg(pixel)
    r, g, b = r(pixel), g(pixel), b(pixel)
    [r / (r + g + b).to_f, g / (r + b + g).to_f]
    end

    def self.distance(pixel, poxel)
    x, y = to_rg(pixel), to_rg(poxel)
    a, b = x[0] - y[0], x[1] - y[1]

    # Divide by 1.41 to get results from 0 to 1
    Math.sqrt((a * a) + (b * b)) / Math.sqrt(2)
    end
    end

    module SelectiveColor
    def to_selective_color(color, avoid = nil)
    pixels.map! do |pixel|
    too_far = color.inject(false){|r, (c, d)| r or (ChunkyPNG::Color.distance(c, pixel) > d)}
    too_close = avoid && avoid.inject(false){|r, (c, d)| r or (ChunkyPNG::Color.distance(c, pixel) < d)}
    if too_far or too_close
    ChunkyPNG::Color.to_grayscale(pixel)
    else
    pixel
    end
    end

    return self
    end
    end

    image = ChunkyPNG::Image.from_file("input.png")

    image.extend(SelectiveColor)
    image.extend(SelectiveColor, Neighbors)


    keep = [[ChunkyPNG::Color.rgb(152,216,56), 0.1]]
    keep = [[ChunkyPNG::Color.rgb(221,57,42), 10]]#[[ChunkyPNG::Color.rgb(152,216,56), 0.1]]

    avoid = [[ChunkyPNG::Color.rgb(255,229,62), 0.05]]
    avoid = nil #[[ChunkyPNG::Color.rgb(255,229,62), 0.05]]

    image.to_selective_color(keep, avoid)
    image.to_selective_color(keep)

    image.save("output.png")
  8. @rogerbraun rogerbraun revised this gist Sep 13, 2011. 4 changed files with 45 additions and 1 deletion.
    Binary file added input.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
    Binary file added output.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
    1 change: 0 additions & 1 deletion r
    Original file line number Diff line number Diff line change
    @@ -1 +0,0 @@
    r
    45 changes: 45 additions & 0 deletions selective_color.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,45 @@
    require "chunky_png"

    module ChunkyPNG::Color
    def self.to_rg(pixel)
    r, g, b = r(pixel), g(pixel), b(pixel)
    [r / (r + g + b).to_f, g / (r + b + g).to_f]
    end

    def self.distance(pixel, poxel)
    x, y = to_rg(pixel), to_rg(poxel)
    a, b = x[0] - y[0], x[1] - y[1]

    # Divide by 1.41 to get results from 0 to 1
    Math.sqrt((a * a) + (b * b)) / Math.sqrt(2)
    end
    end

    module SelectiveColor
    def to_selective_color(color, avoid = nil)
    pixels.map! do |pixel|
    too_far = color.inject(false){|r, (c, d)| r or (ChunkyPNG::Color.distance(c, pixel) > d)}
    too_close = avoid && avoid.inject(false){|r, (c, d)| r or (ChunkyPNG::Color.distance(c, pixel) < d)}
    if too_far or too_close
    ChunkyPNG::Color.to_grayscale(pixel)
    else
    pixel
    end
    end

    return self
    end
    end

    image = ChunkyPNG::Image.from_file("input.png")

    image.extend(SelectiveColor)


    keep = [[ChunkyPNG::Color.rgb(152,216,56), 0.1]]

    avoid = [[ChunkyPNG::Color.rgb(255,229,62), 0.05]]

    image.to_selective_color(keep, avoid)

    image.save("output.png")
  9. rogerbraun created this gist Sep 13, 2011.
    1 change: 1 addition & 0 deletions r
    Original file line number Diff line number Diff line change
    @@ -0,0 +1 @@
    r