Python 3:将图像转换为灰度
我正在尝试做 John Zelle 的“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 行,位于
主要()
文件“C:\Python31\grayscale.py”,第 22 行,位于 main
r, g, b = image.getPixel(行, 列)
文件“C:\Python31\lib\graphics.py”,第 810 行,在 getPixel
值 = 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: 坐标超出范围
我知道我可能需要将图像的锚点更改为中心。但我只能通过图像的宽度和高度来确定,并且我必须先上传图像才能获取这些值。有解决方法吗?
I'm trying to do an exercise in John Zelle's "Python Programming: An Introduction to Computer Science". I downloaded a special graphics package for his book (graphics.py, which is on the linked website). The question reads as follows:
Write a program that converts a color image to grayscale. The user supplies the name of a file containing a GIF or PPM image, and the program loads the image and displays the file. At the click of the mouse, the program converts the image to grayscale. The user is then prompted for a filename to store the grayscale image in.
You will probably want to go back and review the Image object from the graphics library (Section 4.8.4). The basic idea for converting the image is to go through it pixel by pixel and convert each one from color to an appropriate shade of gray. A gray pixel created by setting its red, green, and blue components to have the same brightness. So, color_rgb(0, 0, 0)
is black, color_rgb(255, 255, 255)
is white, and color_rgb(127, 127, 127)
is a gray "halfway" in between. You should use a weighted average of the original rgb values to determine the brightness of the gray. Here is the pseudocode for the grayscale algorithm [for some reason the four-space indent is not working on preview]:
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
Note: the pixel operations in the Image
class are rather slow, so you will want to use relatively small images (not 12 megapixels) to test your program.
I've been working on this for hours. This is the latest version of my code:
# 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()
I finally got it so Python's not giving me any error messages. But all the program does is load the image, take a couple of mouse clicks, and then close. I've been entering the input file as U:\My Pictures\yay.gif, and the output file as U:\My Pictures\yay2.gif. But I just searched my computer and U:\My Pictures\yay2.gif doesn't exist. What am I doing wrong? This is NOT for a class by the way--there's no instructor for me to ask.
Maybe I should follow up in the post instead. I added the save function, but I got an image with a 200x200 grayscale box and the rest of it in color. So, here are some lines I changed:
win = GraphWin("rgb", width, height)
for row in range(height):
for column in range(width):
And I get the following error message:
Traceback (most recent call last):
File "C:\Python31\grayscale.py", line 31, in
main()
File "C:\Python31\grayscale.py", line 22, in main
r, g, b = image.getPixel(row, column)
File "C:\Python31\lib\graphics.py", line 810, in getPixel
value = self.img.get(x,y)
File "C:\Python31\lib\tkinter_init_.py", line 3301, in get
return self.tk.call(self.name, 'get', x, y)
_tkinter.TclError: pyimage1 get: coordinates out of range
I understand that I probably need to change the anchor point of the image to the center. But I can only determine that by the image's width and height, and I have to have uploaded the image first to get those values. Is there a workaround?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
最好保持简单。程序要求保存最后忘记的文件,并使用 getMouse() 来获取“当前像素”,您可以使用 getX() 和 getY()。 的更好示例
这是使用 Graphics.py Grayscale.py
Best to keep it simple. The program asks to save the file, which was forgotten at the end, and to use getMouse() to obtain the "current pixel" which you use getX() and getY(). Here is a better sample using graphics.py
grayscale.py
设置后,我没有看到
outfileName
的任何用途 - 换句话说,您似乎永远不会将结果保存到该文件(或任何其他文件,就此而言)。I don't see any use of
outfileName
after it's set -- in other words, you appear to never, ever save the result to that file (or any other file, for that matter).您没有保存图像。请注意,变量 outfileName 从未使用过。您应该将其传递给某种保存函数。快速浏览了一下graphics.py,我认为这就是您所需要的:
编辑
要解决仅转换一个角的问题,请改为执行此操作,您的旧代码仅转换前200x200像素。我还将 range 更改为 xrange,不是必需的,但效率更高。
You aren't saving the image. Notice that the variable outfileName is never used. You should be passing it to some sort of save function. took a quick look at graphics.py, I think this is what you need:
EDIT
To solve the issue with it only converting one corner, do this instead, your old code was only converting the first 200x200 pixels. I also changed range to xrange, not necessary but more efficient.
我知道这是一篇旧文章但是。我认为你的问题是你正在使用的实际图像。将图像分辨率更改为每英寸 200 像素。
I know this is an old post but. I think your problem is the actual image you are using. Change the image resolution to 200 pixels per inch.