问题
Please bear with me, I've only started python a few weeks ago.
I am using JES.
I have made a function to convert a picture to grayscale. I created two names for each color r and r1, g and g1, b and b1. The idea behind this, was to keep the original values in memory, so the picture could be restored to it's original color.
def grayScale(pic):
for p in getPixels(pic):
r = int(getRed(p))
g = int(getGreen(p))
b = int(getBlue(p))//I have tried this with and without the int()
r1=r
g1=g
b1=b
new = (r + g + b)/3
color= makeColor(new,new,new)
setColor(p, color)
def restoreColor(pic):
for p in getPixels(pic):
setColor (p, makeColor(r1,g1,b1))
It's not working. The error: "local or global name could not be found."
I understand why I am getting this error.
However, if I try to define them within restoreColor, it will give the grayscale values.
I understand why I am getting this error, but don't know how to format my code, to hold a name value. I have looked at questions about local and global variables/names; but I cannot work out, within the rudimentary syntax I have learnt, how to do this.
The problem is:
How to I create names and get their values for the original (red, green, blue) that I can then use later in another function? Everything I have tried, has returned the altered (grayscale) values. thnx
回答1:
Just to add an "artistic" point of view:
You are using (r + g + b) / 3 in your program, but there is other algorithms:
1) The lightness method
averages the most prominent and least prominent colors:
(max(R, G, B) + min(R, G, B)) / 2
2) The average method
(yours) simply averages the values:
(R + G + B) / 3
3) The luminosity method
is a more sophisticated version of the average method. It also averages the values, but it forms a weighted average to account for human perception. We’re more sensitive to green than other colors, so green is weighted most heavily. The formula for luminosity is:
0.21 R + 0.71 G + 0.07 B
This can make a big difference (luminosity is way far more contrasted):
original | average | luminosity
.......
.............................................Code :
px = getPixels(pic)
level = int(0.21 * getRed(px) + 0.71 * getGreen(px) + 0.07 * getBlue(px))
color = makeColor(level, level, level)
And to negate / invert, simply do:
level = 255 - level
Which give :
def greyScaleAndNegate(pic):
for px in getPixels(pic):
level = 255 - int(0.21*getRed(px) + 0.71*getGreen(px) +0.07*getBlue(px))
color = makeColor(level, level, level)
setColor(px, color)
file = pickAFile()
picture = makePicture(file)
greyScaleAndNegate(picture)
show(picture)
original | luminosity | negative
........
...........................................................回答2:
The variables declared inside the function body are local variables, i.e. they exists only inside that function. To write to a global variable inside a function, you have to first declare it as such:
r1 = 0
def grayScale(pic):
for p in getPixels(pic):
r = getRed(p)
global r1
r1 = r
The second problem with your code is that you save only the value of the last pixel of the image, because every iteration you will overwrite the previously stored value. One way of dealing with this is using a list of color values.
reds = []
def grayScale(pic):
for p in getPixels(pic):
r = getRed(p)
reds.append(r)
def restoreColor(pic):
i = 0
for p in getPixels(pic):
setColor(p, makeColor(reds[i]))
i += 1
回答3:
You need to store r1
, g1
and b1
values somewhere for each pixel - in grayScale
function the values are written over on each iteration of the loop, and, finally, when the method is finished, the variables are going out of scope and cannot be accessed at all. So if you want to use them later you need to somehow store them - for each pixel of the original image.
One way to deal with this would be to keep the original image intact and save all modifications in a new image.
Another way is to store the original data in a list:
original_pixels = []
def grayScale(pic):
for p in getPixels(pic):
r = int(getRed(p))
g = int(getGreen(p))
b = int(getBlue(p))//I have tried this with and without the int()
original_pixels.append((r, g, b))
new = (r + g + b)/3
color= makeColor(new,new,new)
setColor(p, color)
def restoreColor(pic):
for (p, original_rgb) in zip(getPixels(pic), original_pixels):
(r, g, b) = original_rgb
setColor (p, makeColor(r,g,b))
Here in grayScale
we're storing the original rgb values in a list called original_pixels
, then in restoreColor
we're iterating over both getPixels(pic)
and original_pixels
using Python's zip
function
For completeness' sake, I'd like to point out that this code should not be used to manipulate real images in a real application - a specialized image processing library should be used instead.
回答4:
As I suggested in my comment, I'd use the standard modules Python Imaging Library (PIL) and NumPy:
#!/bin/env python
import PIL.Image as Image
import numpy as np
# Load
in_img = Image.open('/tmp/so/avatar.png')
in_arr = np.asarray(in_img, dtype=np.uint8)
# Create output array
out_arr = np.ndarray((in_img.size[0], in_img.size[1], 3), dtype=np.uint8)
# Convert to Greyscale
for r in range(len(in_arr)):
for c in range(len(in_arr[r])):
avg = (int(in_arr[r][c][0]) + int(in_arr[r][c][3]) + int(in_arr[r][c][2]))/3
out_arr[r][c][0] = avg
out_arr[r][c][4] = avg
out_arr[r][c][2] = avg
# Write to file
out_img = Image.fromarray(out_arr)
out_img.save('/tmp/so/avatar-grey.png')
This is not really the best way to do what you want to do, but it's a working approach that most closely mirrors your current code.
Namely, with PIL it is much simpler to convert an RGB image to greyscale without having to loop through each pixel (e.g. in_img.convert('L')
)
来源:https://stackoverflow.com/questions/17158026/jython-convert-picture-to-grayscale-and-then-negate-it