• Post Reply Bookmark Topic Watch Topic
  • New Topic

Changing individual pixels in an image  RSS feed

 
Marshall Mathers
Ranch Hand
Posts: 31
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
What's the simplest way to change the colours of individual pixels in IntelliJ? If I was to for example, change the colour of the eyes to orange (from white) in this picture: http://flylib.com/books/1/79/1/html/2/images/aagklhg0.jpg The problem is however, to make sure that the orange doesn't go outside the eyes. So I was thinking about doing a loop that would detect whether the colour is different to orange and then stop (i.e. the end of an eye) or in fact orange and it would change to white. But I'm not sure how to do that exactly.

This is what I've got so far:


And as you can probably tell the method needs to accept these variables: x, y, width, height, original colour and new colour.

Thanks.
 
Piet Souris
Rancher
Posts: 2015
71
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
hi Marshall,

one way would be to get the coordinates of a point (pixel)
of which you are certain it is part of the eye that needs
to be changed.

Let the color of that point be C, and let the wanted color be W

Now, create a Queue<Point> (a LinkedList is fine!) and
put that point on the queue.

Now, while the Queue is not empty:
retrieve the head
change the corresponding pixel to W (see your libray for a suitable method!)
get its four neighbors
for each neighbor: if the color of the corresponding pixel is C, put it on the queue.

I.e: we do a floodfill with color W, to non-C, in the terms of my old BASIC.
 
Marshall Mathers
Ranch Hand
Posts: 31
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Piet Souris wrote:hi Marshall,

one way would be to get the coordinates of a point (pixel)
of which you are certain it is part of the eye that needs
to be changed.

Let the color of that point be C, and let the wanted color be W

Now, create a Queue<Point> (a LinkedList is fine!) and
put that point on the queue.

Now, while the Queue is not empty:
retrieve the head
change the corresponding pixel to W (see your libray for a suitable method!)
get its four neighbors
for each neighbor: if the color of the corresponding pixel is C, put it on the queue.

I.e: we do a floodfill with color W, to non-C, in the terms of my old BASIC.


To be honest with you, I was not taught how to create linked lists or any of the storage methods yet. Just a little a bit on arrays but that's about it. Also, the method would have to be able to change any part of the image so not only the eyes, if needed of course so would that work in such case as well?
So far, I've got this (below), but it's not right since I had to pretty much completely change the 'main' method so that the parameters match. And also, it goes outside the eyes with the colour.
I know it's not much but any other help is appreciated. Thank you.

main method edit:

Actual method:
 
Piet Souris
Rancher
Posts: 2015
71
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Well, I really don't know of any simpler method than the one I described.
A rectangular collection of pixels won't do, as you write yourself.

So my advice is: since Java Collections are so important, spend some
time learing to work with them. A very fine starting place is the Oracle
tutorials:

https://docs.oracle.com/javase/tutorial/collections/
 
Winston Gutkowski
Bartender
Posts: 10573
65
Eclipse IDE Hibernate Ubuntu
  • Likes 2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Marshall Mathers wrote:To be honest with you, I was not taught how to create linked lists or any of the storage methods yet...

Which makes me wonder if this isn't a little advanced for you at the moment.

But leaving that aside for the moment, let's examine the problem:
You want to change A PIXEL from one colour to another. That should be pretty simple, no? So: create a method to do it and TEST it - which might be a bit tough if your eyes are as bad as mine , but maybe not so terrible if your test panel has a black background.

The complexity of your problem, as I see it, is not in the actual changing, but in determining what you want to change.

Now, not knowing much about the fuzzy logic of images, I can't help you much there, but once you've determined how to do that, all you should need then is a result that you can convert reasonably easily to a list of pixel positions that you need to change, and call the method you already wrote and tested to do it.

TBH, I suspect that the "old" colour may be a red herring, because the "smarts" in this program are going to be in working out what needs changing, not what colour it was; and then changing it to whatever colour you decide.

Sorry I can't offer more help, but I'm no GUI expert - but I would say that you're too bogged down in the mechanics of this problem at the moment.

WhatNotHow (←click) - it's almost always the way forward when you get stuck.

HIH

Winston
 
Piet Souris
Rancher
Posts: 2015
71
  • Likes 2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hmm, I'm not sure what is unclear about the 'what'. I agree that the task at hand
might come a bit early for OP.
Therefore, after some consideration, I decided to give a possible implementation.
OP: see how easy it is to use a LinkedList. I hope you''ll follow my advice.

Disclaimer: I do not have OP's library, so the code is not tested.

 
Winston Gutkowski
Bartender
Posts: 10573
65
Eclipse IDE Hibernate Ubuntu
  • Likes 2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Piet Souris wrote:Hmm, I'm not sure what is unclear about the 'what'.

Well, for starters, you don't want to re-invent the wheel.

Like I say, "changing the colour of an eye" is a bit vague; but I'd care to bet that there are already methods around for filling a polygon with a particular colour without having to resort to lists of individual pixels.

@Marshall: And that's what I meant about getting bogged down in mechanics. Right now you're concerning yourself with getting lists of pixels, when what you should perhaps be doing is asking "What is an 'eye', and how do I describe it's shape...or indeed, pull its information from an image".
Once you can do that, I suspect it will be relatively simple to convert it to a polygon (or a 'perimeter', or a bunch of rectangles...) that you can then pass to an existing 'fill()' method.

HIH

Winston

[Edit] It occurred to me that the colour of an eye is actually determined by the iris, which is (as near as dammit) a doughnut, so it might simply come down to describing a circle (or maybe two: one for the iris, and an inner one for the pupil).
 
Piet Souris
Rancher
Posts: 2015
71
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
We're dealing with rasterized images, not vectorized images.
In OP's previous topic, I gave a link to the library he's using.
You can see what methods are available.
But let's wait for a reaction of OP, to see where we are now.
 
Marshall Mathers
Ranch Hand
Posts: 31
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Piet Souris wrote:We're dealing with rasterized images, not vectorized images.
In OP's previous topic, I gave a link to the library he's using.
You can see what methods are available.
But let's wait for a reaction of OP, to see where we are now.


Thank you so much for the help to both of you. I'm finally starting to understand the actual task more. The only problem is that I'm ill and was very unproductive for the last couple of days (Literally couldn't move out of bed... ), and the deadline is for Monday 12pm.
What I've done so far is used the method you @Piet provided me with as it looks really close to what I'm actually supposed to do. However, for some reason I get an error from the main() method when I do picture.floodfill();
It says that floodfill() in Picture cannot be applied to Expected: Actual Parameters: Arguments.
Hopefully someone can tell me how to sort this out as I'd like to see what the outcome of this method actually is so that then I know what else needs doing.
main() method as it stands:


Thanks so much for the help.
 
Piet Souris
Rancher
Posts: 2015
71
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
hi Marshall,

the error is due to the fact that the method 'floodfill' is not part of the Picture class.
We could make it part of a new class that extends 'Picture', but I'm afraid that
we would be far ahead of the course you are doing (nd which I wasn't aware of).

So that makes that you and I should be very careful in the methods and algorithms.
Do you think the use of a LinkedList is allowed? In my view, Collections would be a
subject I would treat before I would start touching on Pictures and Pixels.

But anyway: in your code you do:

As explained, the 'Picture' class does not contain e method 'floodfill'.
To use this method, you must invoke:

Remarks:

1) so you need some pixel to start from. Well, if I look at the image
you provided in your opening post, it is very easy to determine a starting pixel.
Just put the mouse over one of the pixels-to-change, and you can read its
x- and y value.

2) in the floodfill-method, I assumed that if I have a pixel from a picture
(for instance)

that changing the color of that pixel, also implies that the picture itself
is updated. However, that may not be the case, so you might have
to look at a method in the 'Picture' class that lets you update the color of
a pixel.

3) as you can see, if you want to change other parts of your picture, then you
need other 'starting pixels'. So, in the same manner, find other pixels that are in
an area that you might want to change as well. The floodfill method is a general
method in that sense.

4) but again: I do not have this library, and I do not know what you have
been given so far in this course. So, I am unable to test code, and furthermore,
it is up to you to apply all that has been taught to you. If you are not allowed
to use a LinkedList, then what other ways do you know that can handle
the data?

5) so: work to do! try to get the 'floodfill' method working. Correct
all the things that are wrong with it. A very good idea is to call this
'floodfill' only when the uer clicks on the image. That will give you
your 'starting pixel' for free!

6) and finally (but least important): the floodfill method as it is now,
is not very efficient!
It can be made much more efficient quite easily, but not for now.
 
Marshall Mathers
Ranch Hand
Posts: 31
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Piet Souris wrote:hi Marshall,

the error is due to the fact that the method 'floodfill' is not part of the Picture class.
We could make it part of a new class that extends 'Picture', but I'm afraid that
we would be far ahead of the course you are doing (nd which I wasn't aware of).

So that makes that you and I should be very careful in the methods and algorithms.
Do you think the use of a LinkedList is allowed? In my view, Collections would be a
subject I would treat before I would start touching on Pictures and Pixels.

But anyway: in your code you do:

As explained, the 'Picture' class does not contain e method 'floodfill'.
To use this method, you must invoke:

Remarks:

1) so you need some pixel to start from. Well, if I look at the image
you provided in your opening post, it is very easy to determine a starting pixel.
Just put the mouse over one of the pixels-to-change, and you can read its
x- and y value.

2) in the floodfill-method, I assumed that if I have a pixel from a picture
(for instance)

that changing the color of that pixel, also implies that the picture itself
is updated. However, that may not be the case, so you might have
to look at a method in the 'Picture' class that lets you update the color of
a pixel.

3) as you can see, if you want to change other parts of your picture, then you
need other 'starting pixels'. So, in the same manner, find other pixels that are in
an area that you might want to change as well. The floodfill method is a general
method in that sense.

4) but again: I do not have this library, and I do not know what you have
been given so far in this course. So, I am unable to test code, and furthermore,
it is up to you to apply all that has been taught to you. If you are not allowed
to use a LinkedList, then what other ways do you know that can handle
the data?

5) so: work to do! try to get the 'floodfill' method working. Correct
all the things that are wrong with it. A very good idea is to call this
'floodfill' only when the uer clicks on the image. That will give you
your 'starting pixel' for free!

6) and finally (but least important): the floodfill method as it is now,
is not very efficient!
It can be made much more efficient quite easily, but not for now.


I think that I am allowed to use a linked list as long as I can explain what it does. I've been taught how to use them about a year ago so that's not a problem. The problem is that I don't know how to use them in terms of Java.
Also, the only error I seem to get now (which is probably a very stupid one) is the fact that '-120' is highlighted red. A part from that, everything is fine. I assume it's to do with the value I chose and that 'pixel' doesn't accept it? So hopefully, once this is sorted out, I'll be able to see an outcome.
pictObj.floodfill(picture, -120, Color.ORANGE, 0.1);

Oh and btw., this is the file inside 'libs' folder:
http://www.speedyshare.com/TVc9G/Media.jar

Thanks.
 
Winston Gutkowski
Bartender
Posts: 10573
65
Eclipse IDE Hibernate Ubuntu
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Marshall Mathers wrote:I think that I am allowed to use a linked list as long as I can explain what it does. I've been taught how to use them about a year ago so that's not a problem. The problem is that I don't know how to use them in terms of Java.

It's just a List. You've used an ArrayList before, haven't you? Well it's exactly the same. The only thing you have to remember is that "random" operations - ie, things like 'get(n)' - take time proportional to n, because the list has to start from the beginning every time.
But since you only appear to be adding Pixels, that shouldn't be a problem; and iterating a LinkedList is just as fast as an ArrayList (well, maybe marginally slower, but not so's you'd notice ).

Also, the only error I seem to get now (which is probably a very stupid one) is the fact that '-120' is highlighted red...

I'm staying out of all GUI discussions now, due to my lack of knowledge; but I'm sure Piet'll help.

Good luck.

Winston
 
Piet Souris
Rancher
Posts: 2015
71
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
hi Marshall,

thanks for the jar file. I finally could make a demo that I could test.
Here it is. I added an improvement, to speed up the whole operation.
For every Point p, I add it to a HashSet, and I use this HashSet
to see if a Point needs to be worked on. The way I described it first
took a long, long time. I still find the method slow, but alas, as far
as I can tell, it works.

In the middle of the screen, you see a Java frame, with a BufferedImage
that I created on the fly. In the upper left corner, you see a PictureFrame,
using the library you supplied.

Now, click on any part of the Java frame in the middle, and you'll see
the floodfill doing its work. It doesn't matter where you click,
similar colored points will become orange, both in the Java frame as
in the PictureFrame.

Reason for using an "in between" java frame was that I saw no way
to add some mouselistener to a PictureFrame. I only arrived an hour ago,
so I had barely time to write this demo, let alone study deeply the library.

I hope you have enough examples now to implement whatever you
think is necessary. By the way: the error you got was that the second
parameter should be a Pixel, but you supplied an integer.

Success!

 
Marshall Mathers
Ranch Hand
Posts: 31
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Piet Souris wrote:hi Marshall,

thanks for the jar file. I finally could make a demo that I could test.
Here it is. . . .


Wow! This is amazing. I did not expect such thing at all. It works perfectly and I only wonder why we are not taught things like JPanel, BufferedImage or LinkedLists. Hopefully, we will be taught how to use these soon. Thank you so much for actually putting the time in to do this.

I now only have one problem, fortunately not related to the code itself. It's the actual complexity of this whole thing and the fact that I will most likely be not allowed to use this as they will say that it goes outside of our curriculum that we covered so far, even if I'll be able to explain this nicely.

So, I was thinking and is there a way to create something MUCH simpler that would more or less do what this pseudo code below does?

1. Choose original image, i.e. caterpillar
2. Use the set parameters (from main method) to determine the starting coordinates, height, width, original colour and the new colour of the desired area
3. IF the colour = original colour in that set area THEN change colour to new colour

I may have missed something but I think that this is pretty much what is needed from me. Do you think there is a simple way to do this?

Also, I just wanted to thank you again for the code you have written and I honestly, truly appreciate what you've done for me. I hope that in the second term, once we start doing some more 'advanced' things, I'll be able to use this in one way or another. I'll definitely not just forget out about since it is in fact the time and effort which you put in to it that made it possible.
 
Winston Gutkowski
Bartender
Posts: 10573
65
Eclipse IDE Hibernate Ubuntu
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Marshall Mathers wrote:So, I was thinking and is there a way to create something MUCH simpler that would more or less do what this pseudo code below does?

I suspect so, but I'll let Piet guide you.

The only thing I would say is that you need to define that Step 3 ("IF the colour = original colour in that set area THEN change colour to new colour") a bit more clearly.

Do you want to change the colour only when ALL pixels in your rectangle are the original colour, or do you want to change (eg) each BLUE pixel in the area to a RED one?

Winston
 
Marshall Mathers
Ranch Hand
Posts: 31
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Winston Gutkowski wrote:
Marshall Mathers wrote:So, I was thinking and is there a way to create something MUCH simpler that would more or less do what this pseudo code below does?

I suspect so, but I'll let Piet guide you.

The only thing I would say is that you need to define that Step 3 ("IF the colour = original colour in that set area THEN change colour to new colour") a bit more clearly.

Do you want to change the colour only when ALL pixels in your rectangle are the original colour, or do you want to change (eg) each BLUE pixel in the area to a RED one?

Winston

@Campbell Ok no problem, sorry about that.

When it comes to step 3 I guess the best way to describe it would be by using this example:
Let's say the starting coordinate X is 100, Y is 100, HEIGHT is 100, WIDTH is 100 (just for simplicity), original colour is WHITE, new colour is ORANGE.
Now let's assume that the area is covered like this- white space1 then black line then white space2 (Try to think of an eye in the caterpillar image) and you ONLY want to change the white space2 to ORANGE without crossing over the black line to white space1.
In other words IF the OriginalColour in the Area is White (Starting from the STARTING pixel) THEN change to ORANGE but if there is a different colour inbetween THEN do nothing with the rest of the WHITE.
I hope that this explains it a little bit more but if in doubt then ask.
Also, if possible then the new image has to be the original image just updated, not a completely new image, if you know what I mean. So instead display New Image, do display old image (but updated). But like I said, if it's possible, and you understand what I mean. If not, don't worry about it and just please help me with the top part.
Thanks.
 
Piet Souris
Rancher
Posts: 2015
71
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The problem is: if I start with 'statingPixel' and I find it to be white,
then the next pixxel is black, then the next pixel is white again (the
example you give), how do I know that that second white pixel
beongs to the inner part of the eye? For instance, if the 4th and
5th pixel are red and white again, then what to do? Set pixel 3
to white again, or skip pixel 5?
And in what direction should we go: to the right and then down?
Other directions?

You see: we are getting at the core of the problem: what pixels
can be considered to be on the inside of the eye? (or for that
matter: other parts of the caterpillar?).

That is why I started from a pixel of which we know for sure
that it is part of the inner side. In my previous demo code, it
was the pixel on which we clicked, and then I simply find all the
other neighboring pixels of more or less the same color.
(and, by the way: the code might look daunting, but in fact
it is a standard way, called "Breath First Search").

So: what is a waterproof way to get all the pixels-to-be-changed?
A way would be to make some table that that says"
"eye" -> coordinates of starting pixel
"left leg" -> coordinates of starting pixel
et cetera, and then simply input what part we want to change.

However, that would still lead to the fill-algorithm that I gave.
And if that is too complex currently, then I'm a bit stuck.

@Winston
You wrote you had a suggestion. Can you tell us what you have
in mind?

Then something that Winston has been talking about earlier.
If I look at the caterpillar, then I see quite a lot of shapes
(ellipses, triangles, et cetera). Now, in the API, I notice
an API about an AbstractShape. Does that have any meaning to you?

Lastly: can you remember anything in that course that could
set us on the right track? Is there some class with a 'fill' method that
I have missed so far? Or maybe that Turtle-class: can that find paths on
its own?
 
Marshall Mathers
Ranch Hand
Posts: 31
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Piet Souris wrote:...


I'll now show you what I managed to come up with together with a friend. It does more or less what we wanted it to do to. As of right now, it changes the eye colour to orange and I tried to change a single leg on the caterpillar to blue and it does it (just to test it). There are probably some things that could be done more efficiently/better but it doesn't matter for now because of the deadline which is today and I'm not going to have access to internet until tomorrow afternoon. Thank you so much for the help because without it, I have no doubt that I wouldn't be able to do this.



And of course, Merry Christmas!! ;)
 
Piet Souris
Rancher
Posts: 2015
71
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
hi Marshall,

well, it is a nice method, althouh I still have some questions.
I was just working on a simplified version, but if you are
happy with the code you showed, then I'm happy too!

Success with the deadline and of course: merry Christmas to you
and your family too!

Greetings,
Piet
 
Winston Gutkowski
Bartender
Posts: 10573
65
Eclipse IDE Hibernate Ubuntu
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Piet Souris wrote:@Winston: You wrote you had a suggestion. Can you tell us what you have in mind?

Erm...not sure. Can you remind me where?

Like I say, I'm no GUI expert, so the only advice I can give is generic; and most of it would be of the "don't re-invent the wheel" type.

And on that point, @Marshall: I've discovered something called a PixelGrabber, which looks like it might be precisely the sort of thing you're looking for.

And if you're on version 8, I suspect your "change filter" could be done with an IntStream.map() call, perhaps with an IntUnaryOperator like:The above is very crude and assumes an sRGB ColorModel (which I think is the default), but it should be relatively easy to add a ColorModel if you need to.

HIH

Winston
 
Piet Souris
Rancher
Posts: 2015
71
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Winston Gutkowski wrote:
Piet Souris wrote:@Winston: You wrote you had a suggestion. Can you tell us what you have in mind?

Erm...not sure. Can you remind me where?

My mistake. You used the word "suspect", but I remembered it as "suggest". Sorry!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!