Преобразование изображений в оттенки серого в Python

0
class PPM(object):
    def __init__(self, infile, outfile):
        self.infile=infile
        self.outfile=outfile

        #Read in data of image
        data= open(self.infile,"r")
        datain=data.read()
        splits=datain.split()

        #Header info
        self.type=splits[0]
        self.columns=splits[1]
        self.row=splits[2]
        self.colour=splits[3]
        self.pixels=splits[4:]

    def greysscale():
            for row in range(rows):
                for column in range(columns):
                    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))


    def flattenred():
        for colour in range (0,len(self.pixels),3):
            self.pixels [colour]=str[0]

        return picture

    def writetofile(self):
        dataout= open(self.outfile,"w")
        dataout.write(self.type +"\n" + self.columns + "\n" + self.row +"\n"+ self.colour +"\n"+ " ".join (self.pixels))


sample= PPM("cake.ppm", "Replica.ppm")
sample.writetofile()

У меня возникла проблема с записью функции grey_scale, которая изменит изображение на изображение с серой шкалой, усреднив значения всех трех цветов для пикселя, красного, зеленого и синего, а затем заменив их на это среднее значение.
Так что, если бы три цвета были 25, 75 и 250, средний был бы 116, и все три числа стали бы 116.
Как мне это сделать?

  • 0
    Я предполагаю, что вам не разрешено использовать PIL / Pillow для этого, верно?
  • 0
    Что не так с ответом, который я дал здесь? stackoverflow.com/questions/21031546/...
Показать ещё 1 комментарий
Теги:
image-processing
image

3 ответа

0
Лучший ответ
rom_file= [0,3,1]
#Main Function which adds s dots and xs to the deck list(s) depending on the data input file
def main():
    #Container for the output of the program, each nested list contains one row of the output
    decks = [[], [], [], [], []]
    #list that contains the number of empty rows for inputs 1-5(location of input given by [each - 1])
    empty_rows = [4, 3, 2, 1, 0]
    #Scan through each element of the list
    for each in from_file:
        #If the element 'each' is equal to 0, append a single dot to all 5 rows
        if each == 0:
            for i in range(5):
                decks[i].append('.')
        #If the input is in the range 1-5, define variables and the nested for loops
        else:
            #Maximum width of each pyramid
            max = (each * 2) - 1
            half_dots = int((max - 1) / 2)
            base_x = 1
            loc = each - 1
            #For loop that appends the max. number of dots to rows depending on data in empty_rows
            for every in range(empty_rows[loc]):
                decks[every].append(max * '.')
            #Primary for loop; appends the dots and xs to any row not covered by the previous loop (ALl rows that do not already have max dots) for each between 1-5
            for i in range(each):
                decks[i + empty_rows[loc]].append(half_dots * '.')
                decks[i + empty_rows[loc]].append(base_x * 'x')
                decks[i + empty_rows[loc]].append(half_dots * '.')
                half_dots -= 1
                base_x += 2
    #A loop that print out the results
    for each in decks:
        text = ""
        for i in each:
            text += i
        print(text)


#Starts the program by calling the main function
main()
1

У тебя тяжелая часть права, есть много других мелочей, с которыми тебе нужно иметь дело.

Ваша первая проблема заключается в том, что вы никогда не называете функцию greysscale нигде, поэтому все, что вы там ставите, не принесет никакой пользы. Скорее всего, вам нужно что-то подобное в конце:

sample = PPM("cake.ppm", "Replica.ppm")
sample.greysscale()
sample.writetofile()

Вы также ошибочно grey_scale, оба оставляли _ и добавляли дополнительные s, поэтому, если ваш учитель является наклейкой, вы можете быть выделены для этого.

Ваша следующая проблема заключается в том, что метод должен принимать параметр self. Вы сделали это правильно для __init__ и writetofile; вам просто нужно сделать то же самое здесь.

Далее, вы пытаетесь использовать переменные rows и columns и image, которые не существуют в любом месте. У вас есть аналогичные значения, доступные как self.row, self.columns и self.pixels, но вы должны использовать значения, которые у вас есть, а не похожие.

self.row и self.columns - это строки, а не числа; вам нужно преобразовать их с помощью int. Пока мы на нем, гораздо яснее назвать первый self.rows.

И pixels кажутся массивом строк, разделенных на пробелы. Это на самом деле не полезно вообще. Если вы посмотрите на файл PPM, то после первых трех строк это просто сырые двоичные данные. Любые пробелы просто означают, что какой-то цвет имеет значение 32, что не имеет особого значения. Таким образом, вам нужно только отделить первые четыре значения, а затем оставить остальных в качестве одной большой строки байтов.

Вы определенно не можете вызывать такие методы, как getPixel или setPixel для этой строки. Это всего лишь куча байтов; он понятия не имеет, что это значит. Каждый пиксель имеет три байта, по одному на цвет; столбцы просто идут один за другим, а строки - один за другим. Итак, чтобы получить пиксель в row, column, красный цвет находится в row * self.columns * 3 + column * 3, а зеленые и синие - следующие два. Вы можете использовать срез, чтобы сразу получить все три байта. Но, поскольку это всего лишь строка байтов, каждый из них будет символом; вам нужно вызвать ord на них, чтобы получить байтовые числа, а затем chr чтобы вернуть их обратно. Кроме того, вам не разрешается мутировать строку на месте. Но есть хороший трюк, который мы можем использовать для устранения всех этих проблем - bytearray - это как строка, за исключением того, что она изменена, а ее элементы - это числа, а не однобайтные строки.

Между тем, вы хотите использовать "".join, а не " ".join, или вы добавите дополнительное пространство между каждым байтом, что приведет к поломке файла. Но вам это действительно не нужно - это уже bytearray, который можно использовать как строку.

И, наконец, после того, как вы разделите все эти отдельные биты как целые числа, а не на строки, вы больше не сможете их конкатенировать. Это будет намного проще сделать с format чем вручную преобразовать их обратно в строки, чтобы скомпоновать их. Кроме того, файлы PPM обычно помещают пробел, а не новую строку, между строками и столбцами.

Пока мы это делаем, вам нужно close файлы, которые вы открываете, особенно для файлов, которые вы пишете; в противном случае нет гарантии, что последний блок данных будет сброшен на диск, и вы должны открыть двоичные файлы в двоичном режиме.

Так:

class PPM(object):
    def __init__(self, infile, outfile):
        self.infile=infile
        self.outfile=outfile

        #Read in data of image
        data= open(self.infile,"r")
        datain=data.read()
        splits=datain.split(None, 4)

        #Header info
        self.type=splits[0]
        self.columns=int(splits[1])
        self.rows=int(splits[2])
        self.colour=int(splits[3])
        self.pixels=bytearray(splits[4])

    def grey_scale(self):
            for row in range(self.rows):
                for column in range(self.columns):
                    start = row * self.columns * 3 + column * 3
                    end = start + 3
                    r, g, b = self.pixels[start:end]
                    brightness = int(round(0.299 * r + 0.587 * g + 0.114 * b))
                    self.pixels[start:end] = brightness, brightness, brightness

    def writetofile(self):
        dataout= open(self.outfile, "wb")
        dataout.write('{}\n{} {}\n{}\n{}'.format(self.type, 
                                                 self.columns, self.rows, 
                                                 self.colour, 
                                                 self.pixels))

sample = PPM("cake.ppm", "Replica.ppm")
sample.grey_scale()
sample.writetofile()

Если вы хотите использовать другую формулу яркости, это просто - просто измените линию, которая вычисляет яркость, например:

brightness = int(round((r+g+b)/3.0))

Если у вас на самом деле есть файлы с обычным PPM, а не с обычными PPM файлами (в этом случае... ничего себе, я никогда не видел никого в дикой природе), тогда вы были ближе к вашему парсинг-коду, но все же не хватало одного ключевого элемента.

Вы можете вернуться к splits = detain.split(), а затем splits[4:] будет последовательность всех значений цвета пикселя... но это будет последовательность этих значений цвета пикселя в виде строк. Если вы хотите, чтобы они были целыми числами, вам нужно вызвать int на каждом из них, что вы можете сделать со пониманием списка или вызовом map, например:

self.pixels=map(int, splits[4:])

Затем у вас есть последовательность чисел, как и bytearray, поэтому весь этот код может быть одним и тем же... вплоть до вывода, где вы хотите преобразовать их обратно в строки, разделенные пробелами, чтобы создать новый простой PPM. Ваше первоначальное join почти работает, за исключением того, что вы не можете присоединиться к целым числам; вы должны сначала преобразовать их в строки. Опять же, вы можете сделать это, используя map на функции str:

pixelstring = " ".join(map(str, self.pixels))
dataout.write('{}\n{} {}\n{}\n{}'.format(self.type, 
                                         self.columns, self.rows, 
                                         self.colour, 
                                         pixelstring))
  • 0
    Мне нужно сделать это с помощью формулы яркости = int (round ((r + g + b) / 3))
  • 0
    как я могу изменить формулу шкалы серого, чтобы яркость = int (round ((r + g + b) / 3))
Показать ещё 4 комментария
0

Я вижу, что вы делаете преобразование YCrCb в своей строке:

brightness = int(round(0.299 * r + 0.587 * g + 0.114 * b))

Просто измените это на:

brightness = int(round( (r + g + b) / 3 ))

редактировать

Я должен добавить, что способ, которым вы являетесь, на самом деле является лучшим способом сделать преобразование (хотя технически вы создаете яркость, а не яркость). Результат в большей степени соответствует тому, как человеческий глаз воспринимает серых. Вот довольно легко прочитать ссылку на эту тему - http://www.johndcook.com/blog/2009/08/24/algorithms-convert-color-grayscale/ Вы можете видеть, как выглядит преобразование яркости. Преобразование, которое вы использовали (YCrCb), близко к этому, к сожалению, вам нужно будет заставить кого-то с более опытными сказать вам точную разницу.

Edit2

Просто глядя на ответ @abarnert, я не понимал, что у вас была полная программа. Вы должны следовать его совету для улучшения его в целом.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню