Mathematica Stack Exchange is a question and answer site for users of Mathematica. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

Consider the following image:

Red ball in a non-red environment

How can I change all red colors in this image into (for example) blue.

share|improve this question
up vote 39 down vote accepted

Here's a version using Manipulate with a Locator to pick the colour to replace. There is also a tolerance control which determines how wide a range of hues to replace.

i=Import["http://i.stack.imgur.com/Qr7Tx.jpg"];

{h,s,b}=ColorSeparate[i,"HSB"];

colourchange[c_,from_,tol_,to_]:=Module[
{offset=Mod[c-from+0.5,1]-0.5},
If[Abs[offset]>tol,c,to]];

Manipulate[
ColorCombine[
{ImageApply[colourchange[#,ImageValue[h,pos],tol,ColorConvert[to,Hue][[1]]]&,h],s,b},
"HSB"],
{{to,Blue,"Change to"},Blue},
{{tol,-0.01,"Tolerance"},-0.01,0.5},
{{pos,{100,50}},Locator}]

enter image description here

share|improve this answer
1  
You could also add a polygon defined by other locators, to define the mask of impact... – P. Fonseca Apr 27 '12 at 10:11
2  
Or use another locator as a brush – Simon Woods Apr 27 '12 at 10:48
3  
...and I see a full image-processing graphical suit a la Photoshop implemented in Mathematica coming up soon... – István Zachar Apr 27 '12 at 13:25
3  
@Simon Woods: nice approach! I like that one but still: see the two people on the left hand side of the ball? The went blue too. How one avoid that? – John Apr 27 '12 at 18:44

I wanted to change only the color of the ball, leaving all other red objects untouched:

getReds[x_Image] := First@ColorSeparate[x, "Hue"]
isolateSphere[x_Image] := SelectComponents[Binarize[getReds[x], .9], Large]
makeMask[x_Image] := Image@Graphics[ Disk @@ (1 /. 
                        ComponentMeasurements[isolateSphere[x], {"Centroid","BoundingDiskRadius"}]), 
                        {PlotRange -> Thread[{1, #}], ImageSize -> #} &@ImageDimensions@x]
getAreaToChange[x_Image] := ImageMultiply[i, ColorNegate@makeMask[x]]
shiftColors[x_Image] := Image[ImageData[getAreaToChange[x]] /. 
                                                      p: {r_, g_, b_} /; r > .3 :> RotateLeft[p, 1]]
finishIt[x_Image] :=  ImageAdd[ImageMultiply[x, makeMask[x]], ColorConvert[shiftColors[x], "RGB"]]

{#, getReds@#, isolateSphere@#, makeMask@#, getAreaToChange@#, shiftColors@#, finishIt@#} &
                                                       @Import["http://i.stack.imgur.com/Qr7Tx.jpg"]

Mathematica graphics

Comparing side to side:

Mathematica graphics

share|improve this answer
    
Nice. What should one change to change the from and to colors? Or it only works for red and blue? – Rojo Apr 26 '12 at 18:30
    
+1 Nice. What would you have done if there were other instances of red in the picture that you did not want to alter? – DavidC Apr 26 '12 at 18:51
2  
@Rojo In fact Red is the most difficult case, since it is at the beginning and at the end of the Hue[] table. Try Graphics[Raster[Table[{h, s, 1}, {s, 0, 1, .01}, {h, 0, 1, .01}], ColorFunction -> Hue]] – Dr. belisarius Apr 26 '12 at 19:19
6  
@DavidCarraher That happens usually in image processing. Things like "reddish" and "the big thingie in the middle" are not as easy to program as CylindricalDecomposition[] :) – Dr. belisarius Apr 26 '12 at 21:28
2  
Congrats on your (soon to be awarded) populist badge! :) – R. M. Apr 30 '12 at 2:30

A one-liner:

i = Import["http://i.stack.imgur.com/Qr7Tx.jpg"];

Image[ImageData[i] /. {r_, g_, b_} /; r > g && r > b -> {b, g, r}]

enter image description here

share|improve this answer
1  
ImageApply[RotateLeft, i] have a same effect. :) – yode Jun 28 at 8:59

First Method

If you just want to get different color of your ball,but don't want to name the color.I will recommend you this solution,which makes your life easier.In the meantime,it will change other place's color,not just the ball,like CSP's answer

img = Import["http://i.stack.imgur.com/Qr7Tx.jpg"];
Select[ColorCombine /@ Tuples[ColorSeparate[img], {3}], 
 ImageMeasurements[ColorDistance[ColorConvert[#, "Grayscale"], #], 
    "Total"] > 8000 &]

You get 20 different color ball by a line code.


Second Method

If you just want to change your ball's color with a specified color and want maintain other place,like Dr. belisarius' answer,I make a custom function for you to do this

ChangeColor[img_, color_] := 
 Module[{mask = 
    Dilation[
     DeleteSmallComponents[
      ChanVeseBinarize[
       KarhunenLoeveDecomposition[
         ColorCombine /@ Permutations[ColorSeparate[img]]][[1, 2]]]], 
     9]}, ImageAdd[ImageSubtract[img, ImageMultiply[img, mask]], 
   ColorConvert[
    ColorCombine[
     Prepend[Rest[
       ColorSeparate[ColorConvert[ImageMultiply[img, mask], "HSB"]]], 
      First[ColorSeparate[
        ImageMultiply[
         ConstantImage[color, ImageDimensions[img], 
          ColorSpace -> "HSB"], mask]]]], "HSB"], "RGB"]]]

Usage:

ChangeColor[img, #] & /@ RandomColor[5]

share|improve this answer
    
It seems that the background change in the first solution, so I prefer the second one – Wjx Jun 28 at 9:07
    
@Wjx Thanks. :) – yode Jun 28 at 9:10
    
ChanVeseBinarize[] looks to be the key component here. – J. M. Jun 28 at 13:54

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.