Python 3: 将图像转换为灰度图

1 投票
4 回答
14842 浏览
提问于 2025-04-16 04:42

我正在做约翰·泽尔的《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 个回答

1

最好保持简单。这个程序会要求你保存文件,这个步骤在最后可能会被忘记。同时,它会使用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()
1

我知道这是一条旧帖子,但我觉得你的问题可能出在你使用的图片上。把图片的分辨率改成每英寸200像素试试。

3

你没有保存这个图片。注意到变量 outfileName 从来没有被使用过。你应该把它传给某个保存的函数。我快速看了一下 graphics.py,我觉得你需要的是这个:

编辑

为了修复只转换一个角落的问题,改成这样做,你之前的代码只转换了前面 200x200 像素。我还把 range 改成了 xrange,这不是必须的,但更高效。

for row in xrange(height):
        for column in xrange(windth):

撰写回答