如何从Raspberry Pi Camera v2中读取交错二进制数据

时间:2017-03-24 18:58:17

标签: r matrix binary raspberry-pi raster

我正在尝试将未编码的图像用于植被绘图的遥感项目。我的设置是Raspberry Pi 3上的PiCamera v2 NoIR,附带的Roscolux#2007 StoraroBlue凝胶过滤器贴在传感器上,SenseHat用于环境测井。

我可以正常拍摄普通的PNG照片,但我无法弄清楚如何正确读取二进制数据,因为我的所有尝试都会导致条纹混乱。

以下是捕获图像的Python脚本部分:

def picamera_logging_thread():
    logger.info('Started camera logging thread')
    while time() < start_time + timeout:
        with PiCamera() as camera:
            # set values
            camera.resolution = (3280, 2464)

            # let automatic exposure settle
            sleep(2)
            image_name = 'image_' + str(int(time()))

            # capture in PNG format at native resolution
            camera.capture(os.path.join(image_dir, image_name + '.png'))
            logger.info('Saved image ' + image_name + '.png')

            # let automatic exposure settle
            sleep(2)
            image_name = 'image_' + str(int(time()))

            # capture in unencoded RGB format
            camera.capture(os.path.join(image_dir, image_name + '.bip'), 'rgb')
            logger.info('Saved image ' + image_name + '.bip')

        # delay the specified interval
        sleep(picamera_logging_interval - 4)
    logger.info('Stopped camera logging thread')

start_time = time()

# start logging threads
Thread(target = sensehat_logging_thread).start()
Thread(target = picamera_logging_thread).start()

使用picamera Python库捕获未编码RGB图像的在线文档说明了这一点:

  

生成的RGB数据是交错的。也就是说,给定像素的红色,绿色和蓝色值按此顺序组合在一起。数据的第一个字节是(0,0)处像素的红色值,第二个字节是同一像素的绿色值,第三个字节是该像素的蓝色值。第四个字节是(1,0)处像素的红色值,依此类推。

现在,我收集到这意味着生成的二进制数据将采用标准BIP(Band Interleaved by Pixel)格式,但我不确定他们的措辞是否会将像素分组为行或列,因为他们说第二个像素位于(1,0),这使我认为数据中的第二个像素位于第2行第1列而不是预期的第2列第1行。

我在R中编写了一个脚本,它将数据读取为1字节整数(0 - 255)的矩阵,并将它们添加到三个RasterLayer对象的RasterStack中,每个波段对应一个(RGB)。我甚至尝试添加.hdr文件并在QGIS中打开它,但它始终是条纹噪音。

这是R脚本:

# This script parses BIP pixel data from a binary file, assuming order band first then rowwise

# imports
#install.packages("raster")
library(raster)

# define filename of binary data
binary_filename <- "image_1490191326.bip"

# define pixel dimensions of the data, width then height
pixel_dimensions <- c(width = 3280, height = 2464)

# open file connection in Binary Read mode
data_file <- file(binary_filename, "rb")

# get data (and upshift)
binary_data <-
  readBin(
    data_file,
    what = "int",
    size = 1,
    n = pixel_dimensions["height"] * pixel_dimensions["width"] * 3 # hopefully the number of bytes in the file
  ) + 128 # upshift data from (-128, 127) to (0, 255) by adding 128

# close connection to file
close(data_file)

# create red raster layer of every 3rd byte, starting at the first one
red <-
  raster(
    matrix(binary_data[seq(from = 1,
                           to = length(binary_data),
                           by = 3)], nrow = pixel_dimensions["width"], ncol = pixel_dimensions["height"]),
    ymn = pixel_dimensions["height"] / 2 * -1,
    ymx = pixel_dimensions["height"] / 2,
    xmn = pixel_dimensions["width"] / 2 * -1,
    xmx = pixel_dimensions["width"] / 2
  )
names(red) <- "red"

# create green raster layer of every 3rd byte, starting at the second one
green <-
  raster(
    matrix(binary_data[seq(from = 2,
                           to = length(binary_data),
                           by = 3)], nrow = pixel_dimensions["width"], ncol = pixel_dimensions["height"]),
    ymn = pixel_dimensions["height"] / 2 * -1,
    ymx = pixel_dimensions["height"] / 2,
    xmn = pixel_dimensions["width"] / 2 * -1,
    xmx = pixel_dimensions["width"] / 2
  )
names(green) <- "green"

# create blue raster layer of every 3rd byte, starting at the third one
blue <-
  raster(
    matrix(binary_data[seq(from = 3,
                           to = length(binary_data),
                           by = 3)], nrow = pixel_dimensions["width"], ncol = pixel_dimensions["height"]),
    ymn = pixel_dimensions["height"] / 2 * -1,
    ymx = pixel_dimensions["height"] / 2,
    xmn = pixel_dimensions["width"] / 2 * -1,
    xmx = pixel_dimensions["width"] / 2
  )
names(blue) <- "blue"

# create raster stack of the three layers
rgb_stack <- stack(red, green, blue)

# plot hopefully correct raster
plot(rgb_stack)
plotRGB(rgb_stack)

# remove unused large data variables from memory
rm(red, green, blue, binary_data)

Here is a link to a Google Drive folder with the binary data, R output, and a JPG version of the PNG image.

我在这里做错了什么?我怎么读这个并提取可用的像素数据?

1 个答案:

答案 0 :(得分:0)

啊哈!我想我已经解决了。图像实际上是在右边和底边填充了一些未使用的像素(在下图中您可以看到黑色),因此在原始图像的情况下,3280x2464的公开尺寸不正确。正确的是3296x2464,如果将这些数字相乘,然后乘以3(对于R,G和B像素),您将获得与您的文件相匹配的文件大小。

您可以使用 ImageMagick RGB文件转换为JPEG,该文件安装在大多数Linux发行版上,可用于macOS / OSX和Windows(以及Raspberry Pi) :

magick -depth 8 -size 3296x2464 image.rgb result.jpg

enter image description here

注意1 :如果您的文件名实际上并未以.rgb结尾,则可以在其前面添加RGB:,以便为ImageMagick提供有关其内容的提示,例如

magick -depth ... -size ... RGB:image.xyz ...

注意2 :如果您使用旧版ImageMagick,请将magick替换为convert

注3 :如果您想使用ImageMagick裁掉黑色填充像素,请使用:

convert -depth 8 -size 3296x2464 image.rgb -trim result.jpg