Python 3: 将图像转换为灰度图
我正在做约翰·泽尔的《Python编程:计算机科学导论》中的一个练习。我下载了他书中用到的一个特别的图形包(graphics.py,可以在链接的网站上找到)。题目是这样的:
写一个程序,把彩色图片转换成灰度图。用户需要提供一个包含GIF或PPM格式图片的文件名,程序会加载这个图片并显示出来。用户点击鼠标后,程序就会把图片转换成灰度图。接着,程序会询问用户要把灰度图保存成什么文件名。
你可能需要回去看看图形库中的Image对象(第4.8.4节)。转换图片的基本思路是逐个像素地处理,把每个像素的颜色转换成合适的灰度。灰色像素是通过将红、绿、蓝三个颜色的亮度设置为相同来创建的。所以,color_rgb(0, 0, 0)
是黑色,color_rgb(255, 255, 255)
是白色,而color_rgb(127, 127, 127)
是中间的灰色。你应该使用原始RGB值的加权平均来确定灰度的亮度。这里是灰度算法的伪代码 [由于某种原因,四个空格的缩进在预览中没有生效]:
for each row in the image:
for each column in the image:
r, g, b = get pixel information for current row and column
brightness = int(round(0.299r + 0.587g + 0.114b))
update the image # to see progress row by row
注意:在Image
类中的像素操作比较慢,所以你可能想用相对小的图片(不要用12百万像素的)来测试你的程序。
我已经在这个问题上花了几个小时。这是我代码的最新版本:
# grayscale.py
from graphics import *
def main():
infileName = input("File name: ")
outfileName = input("Save to: ")
image = Image(Point(100,100), infileName)
width = image.getWidth()
height = image.getHeight()
win = GraphWin("rgb")
image.draw(win)
row = 0
column = 0
win.getMouse()
for row in range(200):
for column in range(200):
r, g, b = image.getPixel(row, column)
brightness = int(round(0.299 * r + 0.587 * g + 0.114 * b))
image.setPixel(row, column, color_rgb(brightness, brightness, brightness))
win.update()
win.getMouse()
win.close()
main()
我终于让Python没有报错了。但是程序只是在加载图片,点击几下鼠标,然后就关闭了。我输入的文件是U:\My Pictures\yay.gif,输出文件是U:\My Pictures\yay2.gif。但是我刚在电脑上搜索了一下,发现U:\My Pictures\yay2.gif并不存在。我到底哪里出错了?顺便说一下,这不是为了上课——我没有老师可以问。
也许我应该在帖子里继续更新。我添加了保存功能,但得到的图片是一个200x200的灰度框,其他部分还是彩色的。所以,这里是我修改的一些代码行:
win = GraphWin("rgb", width, height)
for row in range(height):
for column in range(width):
然后我得到了以下错误信息:
回溯(最近的调用最后):
文件 "C:\Python31\grayscale.py",第31行,
main()
文件 "C:\Python31\grayscale.py",第22行,在main
r, g, b = image.getPixel(row, column)
文件 "C:\Python31\lib\graphics.py",第810行,在getPixel
value = self.img.get(x,y)
文件 "C:\Python31\lib\tkinter_init_.py",第3301行,在get
return self.tk.call(self.name, 'get', x, y)
_tkinter.TclError: pyimage1 get: 坐标超出范围
我明白我可能需要把图片的锚点改到中心。但是我只能通过图片的宽度和高度来确定,而我必须先上传图片才能得到这些值。有没有什么解决办法?
4 个回答
最好保持简单。这个程序会要求你保存文件,这个步骤在最后可能会被忘记。同时,它会使用getMouse()来获取“当前像素”,然后你可以用getX()和getY()来获取这个像素的坐标。下面是一个使用graphics.py的更好的示例。
grayscale.py
from graphics import*
print("This program grayscales images\n")# intro
def grayscale(): # Obtaining file
infile = input('In what file is the image?: ')
outfile = input('What file do you want it saved?: ')
# Using image file to get dynamics of window. You don't have to create a window either to obtain it.
file = Image(Point(0,0), infile)
width = file.getWidth()
height = file.getHeight()
# Getting center point of photo
cWidth = width / 2
cHeight = height / 2
cen = Point(cWidth, cHeight)
# Ready for window
image = Image(cen,infile)
win = GraphWin("Grayscale Image", width, height)
image.draw(win)
# Getting current Pixel for loop
p = win.getMouse()
x = p.getX()
y = p.getY()
for x in range(height):
for y in range(width):
r, g, b = image.getPixel(x, y)
gray = int(round(.299*r + .587*g + .114*b))
image.setPixel(x,y, color_rgb(gray, gray, gray))
# i accidentally mixed my x and y variable and it spit
# out a two-headed cyclops tee hee
win.update()
# Click to exit
image.save(outfile)
win.getMouse()
win.close()
grayscale()
我知道这是一条旧帖子,但我觉得你的问题可能出在你使用的图片上。把图片的分辨率改成每英寸200像素试试。
你没有保存这个图片。注意到变量 outfileName 从来没有被使用过。你应该把它传给某个保存的函数。我快速看了一下 graphics.py,我觉得你需要的是这个:
编辑
为了修复只转换一个角落的问题,改成这样做,你之前的代码只转换了前面 200x200 像素。我还把 range 改成了 xrange,这不是必须的,但更高效。
for row in xrange(height):
for column in xrange(windth):