Python 程序的 Protobuf 解释

问题描述 投票:0回答:1

我得到了一个 protobuf 接口,其中有一个可以旋转 90 度的“图像”。我一直停留在图像表示上,因为它是通过数据类型字节而不是二维矩阵传入的。这是 protobuf 文件:

 syntax = "proto3";

option java_multiple_files = true;
option java_package = "imageRotation";

// A single image which might be grayscale, or color.
//
// When color == false, this image is grayscale.
// In this case, the data is single channel (one byte per pixel)
// and stored row-wise.
//
// When color == true, this is a color image.  In
// this case, the data is 3 channel rgb with the rgb
// triplets stored row-wise (one byte per channel, 3 bytes
// per pixel).
message Image {
    bool color = 1;
    bytes data = 2;
    int32 width = 3;
    int32 height = 4;
}

// A request to rotate an image by some multiple of 90 degrees.
//
// The input image may be color or grayscale.
//
// Positive rotations are counter clockwise.
message ImageRotateRequest {
    enum Rotation {
        NONE = 0;
        NINETY_DEG = 1;
        ONE_EIGHTY_DEG = 2;
        TWO_SEVENTY_DEG = 3;
    }

    Rotation rotation = 1;
    Image image = 2;
}

service ImageService {
    rpc RotateImage(ImageRotateRequest) returns (Image);

}

我很困惑如何将“字节数据”转换为代表图像的 RGB 值网格。

这是我目前的方法:

    # Import the necessary modules and generated protobuf classes
from image_pb2 import Image, ImageRotateRequest, ImageService
from concurrent import futures
import grpc

# Function to rotate an image matrix by the specified number of 90-degree rotations
def rotate_image(image, rotations):
    rotation_mapping = {
        ImageRotateRequest.NONE: 0,
        ImageRotateRequest.NINETY_DEG: 90,
        ImageRotateRequest.ONE_EIGHTY_DEG: 180,
        ImageRotateRequest.TWO_SEVENTY_DEG: 270,
    }

    rotations = rotation_mapping.get(rotations, 0)

    # Extract image details from the request
    is_color = image.color
    width = image.width
    height = image.height

    # Calculate the matrix size based on color and width/height
    matrix_size = width * height * (3 if is_color else 1)

    # Decode the image data from bytes to a matrix
    matrix_values = list(image.data[:matrix_size])

    if is_color:
        # For color images, reshape the matrix to a 3D matrix (3 channels)
        matrix = [matrix_values[i:i+3] for i in range(0, matrix_size, 3)]
    else:
        matrix = [matrix_values]

    # Rotate the matrix based on the request
    rotated_matrix = [list(row) for row in zip(*matrix[::-1])]  # Rotate 90 degrees

    # Flatten the rotated matrix back to a list of values
    rotated_values = [value for row in rotated_matrix for value in row]

    # Create a new Image with rotated values
    rotated_image = Image(
        color=is_color,
        data=bytes(rotated_values),
        width=height,
        height=width  # Swap width and height after rotation
    )

    return rotated_image

# gRPC service implementation
class ImageServiceImpl(ImageService):
    def RotateImage(self, request, context):
        # Rotate the image based on the request
        rotated_image = rotate_image(request.image, request.rotation)

        # Return the rotated image in the response
        return rotated_image

# gRPC server setup
def serve():
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    ImageService.add_RotateImageServicer_to_server(ImageServiceImpl(), server)
    server.add_insecure_port('[::]:50051')
    server.start()
    server.wait_for_termination()

if __name__ == '__main__':
    serve()

因此,我不明白传入的 bytes 参数将如何填充值的宽度 x 高度矩阵。

任何帮助将不胜感激,这是一项艰巨的任务。谢谢!

python matrix byte grpc
1个回答
0
投票

参见:

这很老套,但是:

import grpc
import image_pb2
import image_pb2_grpc

from concurrent import futures

# gRPC service implementation
class ImageService(image_pb2_grpc.ImageServiceServicer):

    def RotateImage(self, request, context):

        # Ensure that the number of bytes matches expection: width*height*bytes(color)
        # Where bytes(color) = 1 (false) and 3 (true)
        got = request.image.width * request.image.height * (3 if request.image.color else 1)
        want = len(request.image.data)

        if got != want:
            context.set_code(grpc.StatusCode.INVALID_ARGUMENT)
            context.set_details("Image data size does not correspond to width, height and color")
            return request.image
        
        # If there's no rotation to perform, shortcut to returning the provided image
        if request.rotation == image_pb2.ImageRotateRequest.NONE:
            return request.image

        # Convert the image to a matrix
        matrix = []
        current = 0
        for y in range(request.image.height):
            row = []
            for x in range(request.image.width):
                if request.image.color:
                    # True (RGB) requires 3 bytes (use tuple)
                    pixel = (
                        request.image.data[current],
                        request.image.data[current+1],
                        request.image.data[current+2],
                    )
                    current += 3
                else:
                    # False (Grayscale) requires 1 byte
                    pixel = request.image.data[current]
                    current += 1

                row.append(pixel)
            # Append row
            matrix.append(row)
        
        print(matrix)

        if request.rotation == image_pb2.ImageRotateRequest.NINETY_DEG:
            print("Rotating: 090")
            matrix = list(zip(*matrix[::-1]))

        if request.rotation == image_pb2.ImageRotateRequest.ONE_EIGHTY_DEG:
            print("Rotating: 180")
            matrix = list(zip(*matrix[::-1]))
            matrix = list(zip(*matrix[::-1]))

        if request.rotation == image_pb2.ImageRotateRequest.TWO_SEVENTY_DEG:
            print("Rotating: 270")
            # Rotate counterclockwise
            matrix = list(zip(*matrix))[::-1]

        # Flatten the matrix
        pixels = []
        for y in range(request.image.height):
            for x in range(request.image.width):
                    if request.image.color:
                        pixels.extend(matrix[y][x])
                    else:
                        pixels.append(matrix[y][x])


        print(f"Result: {pixels}")

        # Revert the flattened matrix to bytes
        data = bytes(pixels)

        # Return the rotated image in the response
        return image_pb2.Image(
            color=request.image.color,
            data=data,
            width=request.image.width,
            height=request.image.height,
        )


# gRPC server setup
def serve():
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    image_pb2_grpc.add_ImageServiceServicer_to_server(ImageService(), server)
    server.add_insecure_port('[::]:50051')
    server.start()
    server.wait_for_termination()

if __name__ == '__main__':
    serve()

重构矩阵处理以便能够单独测试它会很好,但是,例如:

# Rotation: 180
REQUEST="
{
    \"rotation\": 2,
    \"image\": {
        \"color\": ${COLOR},
        \"data\": \"${DATA}\",
        \"width\": 3,
        \"height\": 3
    }
}"

grpcurl \
-plaintext \
-proto image.proto \
-d "${REQUEST}" \
localhost:50051 \
ImageService/RotateImage \
| jq -r .data \
| base64 --decode \
| xxd -g 3

例如灰度

# Want: [[1,2,3],[4,5,6],[7,8,9]]
# Byte: 010203040506070809
# B64: AQIDBAUGBwgJ
DATA="AQIDBAUGBwgJ"
COLOR=false

00000000: 090807 060504 030201  
# Want: [[9,8,7],[6,5,4],[3,2,1]] 

例如颜色

# Want: [[010101,020202,030303], ... ]
# Byte: 010101020202030303...
# B64: AQEBAgICAwMDBAQEBQUFBgYGBwcHCAgICQkJ
DATA="AQEBAgICAwMDBAQEBQUFBgYGBwcHCAgICQkJ"
COLOR=true

00000000: 090909 080808 070707 060606 050505 04
00000010: 040403 030302 020201 0101
# Want [[090909, 080808, 070707], ... ]
© www.soinside.com 2019 - 2024. All rights reserved.