Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/360.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 通过在RGB元组中插入灰度值,使用PIL将灰度图像插入RGB图像_Python_Python Imaging Library - Fatal编程技术网

Python 通过在RGB元组中插入灰度值,使用PIL将灰度图像插入RGB图像

Python 通过在RGB元组中插入灰度值,使用PIL将灰度图像插入RGB图像,python,python-imaging-library,Python,Python Imaging Library,我正在编写几个函数,第一个函数将灰度位图图像插入到另一个彩色位图图像中。现在我的目标基本上是获取灰度像素图像的每个数字(例如123)并替换每个RGB像素(24424244)的结束数字,所以它基本上是这样结束的(24124243)。本质上,这是用灰度图像对彩色图像进行水印 下面的代码是我到目前为止所拥有的,我能够在列表中返回元组值,我只是不知道如何在较大的图像中操纵较小灰度图像大小的空间 def add_watermark(): image = Image.open() pixel

我正在编写几个函数,第一个函数将灰度位图图像插入到另一个彩色位图图像中。现在我的目标基本上是获取灰度像素图像的每个数字(例如123)并替换每个RGB像素(24424244)的结束数字,所以它基本上是这样结束的(24124243)。本质上,这是用灰度图像对彩色图像进行水印

下面的代码是我到目前为止所拥有的,我能够在列表中返回元组值,我只是不知道如何在较大的图像中操纵较小灰度图像大小的空间

def add_watermark():
    image = Image.open()
    pixels = list(image.getdata())
    image.putdata()
    image.save()

    for i in range(img.size[0]):
        for j in range(img.size[1]):
            pixels[i,j] = (i, j, 100)

有人能给你提些建议吗?

你说得对。这就是你操作像素的方式,尽管你可以像我在下面展示的那样使用它更快一点

除了提取和设置正确的数字外,这一切都非常简单。在这个例子中,我通过除以10的幂和使用模运算符来实现,尽管还有其他方法。希望这些评论能很好地解释这一点

from PIL import Image

def add_watermark(watermark_path, image_in_path, image_out_path):
    # Load watermark and image and check sizes and modes
    watermark = Image.open(watermark_path)
    assert watermark.mode == 'L'
    image = Image.open(image_in_path)
    assert image.mode == 'RGB'
    assert watermark.size == image.size

    # Get pixel access objects
    watermark_pixels = watermark.load()
    image_pixels = image.load()

    # Watermark each pixel
    for x in range(image.size[0]):
        for y in xrange(image.size[1]):
            # Get the tuple of rgb values and convert to a list (mutable)
            rgb = list(image_pixels[x, y])
            for i, p in enumerate(rgb):
                # Divide the watermark pixel by 100 (r), then 10 (g), then 1 (b)
                # Then take it modulo 10 to get the last digit
                watermark_digit = (watermark_pixels[x, y] / (10 ** (2 - i))) % 10
                # Divide and multiply value by 10 to zero the last digit
                # Then add the watermark digit
                rgb[i] = (p / 10) * 10 + watermark_digit
            # Convert back to a tuple and store in the image
            image_pixels[x, y] = tuple(rgb)

    # Save the image
    image.save(image_out_path)

如果您对水印图像感兴趣,您可能想看看。例如,它是该概念的有效演示,可以用作存储用作水印的文本的基础。要研究修改图像中的各种像素位如何改变图像的质量,您可能需要在决定覆盖哪些数据之前先尝试一下


数字瞄准具

import cStringIO
from PIL import Image
import bz2
import math

################################################################################

PIXELS_PER_BLOCK = 4
BYTES_PER_BLOCK = 3
MAX_DATA_BYTES = 16777215

################################################################################

class ByteWriter:

    "ByteWriter(image) -> ByteWriter instance"

    def __init__(self, image):
        "Initalize the ByteWriter's internal variables."
        self.__width, self.__height = image.size
        self.__space = bytes_in_image(image)
        self.__pixels = image.load()

    def write(self, text):
        "Compress and write the text to the image's pixels."
        data = bz2.compress(text)
        compressed_size = len(data)
        if compressed_size > self.__space:
            raise MemoryError('There is not enough space for the data!')
        size_data = self.__encode_size(compressed_size)
        tail = '\0' * ((3 - compressed_size) % 3)
        buffer = size_data + data + tail
        self.__write_buffer(buffer)

    @staticmethod
    def __encode_size(number):
        "Convert number into a 3-byte block for writing."
        data = ''
        for _ in range(3):
            number, lower = divmod(number, 256)
            data = chr(lower) + data
        return data

    def __write_buffer(self, buffer):
        "Write the buffer to the image in blocks."
        addr_iter = self.__make_addr_iter()
        data_iter = self.__make_data_iter(buffer)
        for trio in data_iter:
            self.__write_trio(trio, addr_iter.next())

    def __make_addr_iter(self):
        "Iterate over addresses of pixels to write to."
        addr_group = []
        for x in range(self.__width):
            for y in range(self.__height):
                addr_group.append((x, y))
                if len(addr_group) == 4:
                    yield tuple(addr_group)
                    addr_group = []

    @staticmethod
    def __make_data_iter(buffer):
        "Iterate over the buffer a block at a time."
        if len(buffer) % 3 != 0:
            raise ValueError('Buffer has a bad size!')
        data = ''
        for char in buffer:
            data += char
            if len(data) == 3:
                yield data
                data = ''

    def __write_trio(self, trio, addrs):
        "Write a 3-byte block to the pixels addresses given."
        duo_iter = self.__make_duo_iter(trio)
        tri_iter = self.__make_tri_iter(duo_iter)
        for (r_duo, g_duo, b_duo), addr in zip(tri_iter, addrs):
            r, g, b, a = self.__pixels[addr]
            r = self.__set_two_bits(r, r_duo)
            g = self.__set_two_bits(g, g_duo)
            b = self.__set_two_bits(b, b_duo)
            self.__pixels[addr] = r, g, b, a

    @staticmethod
    def __make_duo_iter(trio):
        "Iterate over 2-bits that need to be written."
        for char in trio:
            byte = ord(char)
            duos = []
            for _ in range(4):
                byte, duo = divmod(byte, 4)
                duos.append(duo)
            for duo in reversed(duos):
                yield duo

    @staticmethod
    def __make_tri_iter(duo_iter):
        "Group bits into their pixel units for writing."
        group = []
        for duo in duo_iter:
            group.append(duo)
            if len(group) == 3:
                yield tuple(group)
                group = []

    @staticmethod
    def __set_two_bits(byte, duo):
        "Write a duo (2-bit) group to a pixel channel (RGB)."
        if duo > 3:
            raise ValueError('Duo bits has to high of a value!')
        byte &= 252
        byte |= duo
        return byte

################################################################################

class ByteReader:

    "ByteReader(image) -> ByteReader instance"

    def __init__(self, image):
        "Initalize the ByteReader's internal variables."
        self.__width, self.__height = image.size
        self.__pixels = image.load()

    def read(self):
        "Read data out of a picture, decompress the data, and return it."
        compressed_data = ''
        addr_iter = self.__make_addr_iter()
        size_block = self.__read_blocks(addr_iter)
        size_value = self.__block_to_number(size_block)
        blocks_to_read = math.ceil(size_value / 3.0)
        for _ in range(blocks_to_read):
            compressed_data += self.__read_blocks(addr_iter)
        if len(compressed_data) != blocks_to_read * 3:
            raise ValueError('Blocks were not read correctly!')
        if len(compressed_data) > size_value:
            compressed_data = compressed_data[:size_value]
        return bz2.decompress(compressed_data)

    def __make_addr_iter(self):
        "Iterate over the pixel addresses in the image."
        addr_group = []
        for x in range(self.__width):
            for y in range(self.__height):
                addr_group.append((x, y))
                if len(addr_group) == 4:
                    yield tuple(addr_group)
                    addr_group = []

    def __read_blocks(self, addr_iter):
        "Read data a block at a time (4 pixels for 3 bytes)."
        pixels = []
        for addr in addr_iter.next():
            pixels.append(self.__pixels[addr])
        duos = self.__get_pixel_duos(pixels)
        data = ''
        buffer = []
        for duo in duos:
            buffer.append(duo)
            if len(buffer) == 4:
                value = 0
                for duo in buffer:
                    value <<= 2
                    value |= duo
                data += chr(value)
                buffer = []
        if len(data) != 3:
            raise ValueError('Data was not decoded properly!')
        return data

    @classmethod
    def __get_pixel_duos(cls, pixels):
        "Extract bits from a given group of pixels."
        duos = []
        for pixel in pixels:
            duos.extend(cls.__extract_duos(pixel))
        return duos

    @staticmethod
    def __extract_duos(pixel):
        "Retrieve the bits stored in a pixel."
        r, g, b, a = pixel
        return r & 3, g & 3, b & 3

    @staticmethod
    def __block_to_number(block):
        "Convert a block into a number (size of data buffer)."
        value = 0
        for char in block:
            value <<= 8
            value |= ord(char)
        return value

################################################################################

def main(picture, mode, text):
    "Dispatch the various operations that can be requested."
    image = Image.open(picture)
    if image.mode != 'RGBA':
        image = image.convert('RGBA')
    if mode == 'Evaluate':
        evaluate(image)
    elif mode == 'Simulate':
        simulate(image, text)
    elif mode == 'Encode':
        encode(image, text)
    elif mode == 'Decode':
        decode(image)
    else:
        raise ValueError('Mode %r was not recognized!' % mode)

################################################################################

def evaluate(image):
    "Display the number of bytes available in the image."
    print 'Usable bytes available =', bytes_in_image(image)

def bytes_in_image(image):
    "Calculate the number of usable bytes in an image."
    blocks = blocks_in_image(image)
    usable_blocks = blocks - 1
    usable_bytes = usable_blocks * BYTES_PER_BLOCK
    return min(usable_bytes, MAX_DATA_BYTES)

def blocks_in_image(image):
    "Find out how many blocks are in an image."
    width, height = image.size
    pixels = width * height
    blocks = pixels / PIXELS_PER_BLOCK
    return blocks

################################################################################

def simulate(image, text):
    "Find out how much space the text takes in the image that was given."
    compressed_data = bz2.compress(text)
    compressed_size = len(compressed_data)
    usable_bytes = bytes_in_image(image)
    space_leftover = usable_bytes - compressed_size
    if space_leftover > 0:
        print 'You still have %s more bytes for storage.' % space_leftover
    elif space_leftover < 0:
        print 'You overfilled the image by %s bytes.' % -space_leftover
    else:
        print 'This is a perfect fit!'

################################################################################

def encode(image, text):
    "Encodes text in image and returns picture to the browser."
    mutator = ByteWriter(image)
    mutator.write(text)
    output = cStringIO.StringIO()
    image.save(output, 'PNG')
    output.seek(0)
    print 'Content-Type: image/PNG'
    print output.read()

################################################################################

def decode(image):
    "Extract the original message and deliver it to the client."
    accessor = ByteReader(image)
    buffer = accessor.read()
    print buffer

################################################################################

if __name__ == '__builtin__':
    try:
        main(cStringIO.StringIO(PICTURE), MODE, TEXT)
    except SystemExit:
        pass
导入cStringIO
从PIL导入图像
进口bz2
输入数学
################################################################################
每个块的像素数=4
每个块的字节数=3
最大数据字节数=16777215
################################################################################
类字节编写器:
“字节编写器(图像)->字节编写器实例”
定义初始化(自我,图像):
“初始化字节写入程序的内部变量。”
self.\u宽度,self.\u高度=image.size
self.\uuuu space=图像中的字节(图像)
self.\uu pixels=image.load()
def写入(自身、文本):
“压缩文本并将其写入图像像素。”
数据=bz2.压缩(文本)
压缩大小=长度(数据)
如果压缩大小>自空间:
raise MemoryError('没有足够的空间容纳数据!')
大小\数据=自身。\编码\大小(压缩\大小)
尾部='\0'*((3-压缩的大小)%3)
缓冲区=大小\数据+数据+尾部
自写入缓冲区(缓冲区)
@静力学方法
定义编码大小(数字):
“将数字转换为3字节块进行写入。”
数据=“”
对于范围(3)内的uu:
数字,下限=divmod(数字,256)
数据=chr(较低)+数据
返回数据
定义写入缓冲区(自身,缓冲区):
“将缓冲区以块的形式写入图像。”
addr\u iter=self.\u make\u addr\u iter()
数据输入=自身。数据输入(缓冲区)
对于数据反应堆中的trio:
self.\u write\u trio(trio,addr\u iter.next())
定义制造地址(自身):
“迭代要写入的像素地址。”
地址组=[]
对于范围内的x(自身宽度):
对于范围内的y(自身高度):
addr_group.append((x,y))
如果len(addr_组)==4:
收益元组(addr_组)
地址组=[]
@静力学方法
定义生成数据(缓冲区):
“在缓冲区中一次迭代一个块。”
如果len(缓冲区)%3!=0:
raise VALUERROR('缓冲区大小不正确!')
数据=“”
对于缓冲区中的字符:
数据+=字符
如果len(数据)==3:
产量数据
数据=“”
定义写入三人组(自我、三人组、地址):
“将3字节块写入给定的像素地址。”
duo_iter=self.\u make_duo_iter(三人组)
国际热核聚变实验堆=自行研制的国际热核聚变实验堆(国际热核聚变实验堆)
对于(r_duo,g_duo,b_duo),地址为zip(tri_iter,地址):
r、 g,b,a=自身像素[addr]
r=自身。设置两个位(r,r)
g=自身。设置两个位(g,g)
b=自身。设置两个位(b,b)
自身像素[addr]=r,g,b,a
@静力学方法
def uuu make_uDuo_uiter(三人组):
“对需要写入的2位进行迭代。”
对于三人一组的字符:
字节=ord(字符)
duos=[]
对于范围(4)内的uu:
字节,duo=divmod(字节,4)
二重奏(二重奏)
对于反转的双音组(双音组):
屈服二重奏
@静力学方法
def_uuMake_uTri_uiter(duo_uiter):
“将位分组到它们的像素单位中进行写入。”
组=[]
对于duo_iter中的duo:
分组追加(二人组)
如果len(组)==3:
产量元组(组)
组=[]
@静力学方法
定义设置两位(字节,双):
“将duo(2位)组写入像素通道(RGB)。”
如果duo>3:
raise VALUERROR('Duo bits的值必须高!')
字节&=252
字节|=duo
返回字节
################################################################################
类ByteReader:
“ByteReader(图像)->ByteReader实例”
定义初始化(自我,图像):
“初始化ByterReader的内部变量。”
self.\u宽度,self.\u高度=image.size
self.\uu pixels=image.load()
def读取(自):
从图片中读取数据,解压缩数据,然后返回
压缩的_数据=“”
addr\u iter=self.\u make\u addr\u iter()
大小块=自身。读取块(添加)
大小\值=自。\块\到\号(大小\块)
块到读取=math.ceil(大小值/3.0)
对于范围内的(块读取):
压缩数据+=自读块(地址)
如果len(压缩数据)!=块_至_读取*3:
from cStringIO import StringIO
from PIL import Image
from random import randrange

def main(data, r_bits, g_bits, b_bits, a_bits):
    image = Image.open(data)
    if image.mode != 'RGBA':
        image = image.convert('RGBA')
    width, height = image.size
    array = image.load()
    data.close()
    for x in range(width):
        for y in range(height):
            r, g, b, a = array[x, y]
            r ^= randrange(r_bits)
            g ^= randrange(g_bits)
            b ^= randrange(b_bits)
            a ^= randrange(a_bits)
            array[x, y] = r, g, b, a
    data = StringIO()
    image.save(data, 'PNG')
    print 'Content-Type: image/PNG'
    print data.getvalue()

if __name__ == '__builtin__':
    main(StringIO(DATA), *map(lambda bits: 1 << int(bits), (R, G, B, A)))