Jython convert picture to grayscale and then negate it

跟風遠走 提交于 2019-11-29 12:23:56

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

........

.......................

.........................

...........

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

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.

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'))

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!