将二进制数据从Python GUI管道化到c ++并再次返回

时间:2016-05-03 15:11:23

标签: python pipe stdin qgis msvcrt

我一直致力于一个项目,该项目在用Python编写的QGIS插件和我用C ++编写的一些图像处理代码之间来回传递数据。通过以下两个问题得到一些社区帮助后,我得到了一个基于控制台的示例代码,它可以模拟图像,将其传递给我的C ++代码,进行一些重要的处理,然后将其管道并正确解压缩。我无法将其移植到GUI样式代码。

以前的问题供参考:

Data corruption Piping between C++ and Python

piping binary data between python and c++

目前(我坚信最后)的障碍是,当我从PyDev环境转移到我的QGIS插件(基于GUI)时,我将stdin和stdout置于二进制模式的能力会引发错误。

我从PyDev运行的Python代码是:

import subprocess
import struct
import sys
import os, msvcrt
msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
import numpy as np
import datetime

#set up the variables needed 
bytesPerDouble = 8
sizeX = 2000
sizeY = 2000
offset = sizeX*sizeY
totalBytesPerArray = sizeX*sizeY*bytesPerDouble
totalBytes = totalBytesPerArray*2                   #the 2 is because we pass 2 different versions of the 2D array

#setup the testing data array 
a = np.zeros(sizeX*sizeY*2, dtype='d')
for i in range(sizeX):
    for j in range(sizeY):
        a[j+i*sizeY] = i
        a[j+i*sizeY+offset] = i
        if i % 10 == 0:
           a[j+i*sizeY+offset] = j

data = a.tobytes('C')      

strTotalBytes = str(totalBytes)
strLineBytes  = str(sizeY*bytesPerDouble)

#communicate with c++ code
print("starting C++ code")     
command =   "C:\Python27\PythonPipes.exe"
proc = subprocess.Popen([command, strTotalBytes, strLineBytes, str(sizeY), str(sizeX)], stdin=subprocess.PIPE,stderr=subprocess.PIPE,stdout=subprocess.PIPE)

ByteBuffer = (data)
proc.stdin.write(ByteBuffer)

starttime = datetime.datetime.now()

print("Getting Status from C++")
for i in range(sizeX-6):
    returnvalues = proc.stdout.read(4)
    a = buffer(returnvalues)
    b = struct.unpack_from('i', a)
    currenttime = datetime.datetime.now()
    deltatime = (currenttime-starttime).total_seconds()
    print "ETA for processing completion " + str( ((sizeX + 0.0) / (b[0] + 0.0) - 1.0)*deltatime) + " Seconds"


print("Reading results back from C++")
for i in range(sizeX):
    returnvalues = proc.stdout.read(sizeY*bytesPerDouble)
    a = buffer(returnvalues)
    b = struct.unpack_from(str(sizeY)+'d', a)
    print str(b) + " " + str(i)

print('done')

当我使用此代码将此代码移动到我的QGIS模块(使用插件生成器和QtCreator构建)时:

import resources
from qgis.core import *
import qgis.utils
import time
import struct
import subprocess
import os, msvcrt
import sys

msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)

import datetime




class CreateRasterLayer:


    def __init__(self, ex_iface):
        self.iface = ex_iface


    def setupImageSpacing(self):
        #grab the layers in QGIS
        layers = self.iface.legendInterface().layers()

        #grab "gsd" per pixel
        self.deltaX = (layers[0].extent().xMaximum() -layers[0].extent().xMinimum())/layers[0].width()
        self.deltaY = (layers[0].extent().yMaximum() -layers[0].extent().yMinimum())/layers[0].height()

        #get overlap of layers
        self.AOI = layers[0].extent().intersect(layers[1].extent())

        self.width  = int((self.AOI.xMaximum() - self.AOI.xMinimum()) // self.deltaX)
        self.height = int((self.AOI.yMaximum() - self.AOI.yMinimum()) // self.deltaY)

        print(self.AOI.asWktCoordinates())
        print(self.width)
        print(self.height)
        entropyRadius = 7
        self.CalculateEntropy(layers, entropyRadius)  

    def CalculateEntropy(self, layers, radius):
        #variables used in this Python Script
        bytesPerNumber = 8                          # Python uses 8 bytes for all floating point numbers
        bytesPerColumn = self.height*bytesPerNumber # This is the number of bytes in one column of data. data will be passed to c++ program 1 column at a time over pipes
        bytesPerLayer = self.width* bytesPerColumn  # This is the number of bytes in one of the layers that is going to e sent to the c++ program
        RedBytes = bytearray(bytesPerLayer*2)       # Byte array that will be passed to the C++ array. this holds the Red channel data for the layer for testing purposes.

        #arguments that will be passed to the c++ program  
        strTotalBytes = str(bytesPerLayer*2)        #number of bytes that will be passed to the C++ program total
        strLineBytes  = str(bytesPerColumn)         #number of bytes that will be passed to the C++ program at a time
        strHeight       = str(self.height)               #number of doubles that are being passed to the C++ program at a time
        strWidth        = str(self.width)                #number of data data passes to the C++ program need to completely transfer one layer object

        #start the C++ program 
        print("starting C++ code for processing layers")   
        command = ["C:\Python27\PythonPipes.exe", strTotalBytes , strLineBytes , strHeight, strWidth]

        proc = subprocess.Popen( command, stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE)

        print("Piping layer 1 -> C++")
        print(time.ctime(time.time()))
        currentlayer = 0
        value = bytearray(bytesPerColumn)

        #read the data in the first layer
        for i in range(self.width):
            for j in range(self.height):
                #calculate the index of the byte array where this data should be placed
                currentindex = bytesPerLayer*currentlayer + (j+i*self.height)*bytesPerNumber 
                #retrieve the value of the pixel at the current raster  layer location
                pixelData0 = layers[0].dataProvider().identify(QgsPoint(self.AOI.xMinimum()+i*self.deltaX, self.AOI.yMinimum()+j*self.deltaY),QgsRaster.IdentifyFormatValue)
                #convert the pixel data for the Red Channel into it's 'C' byte ordering and assign it to the RedByte Array
                RedBytes[ currentindex: currentindex + bytesPerNumber] = struct.pack('d',pixelData0.results()[1])
            #copy bytes into the Buffer for piping    
            RedBuffer = buffer(RedBytes, bytesPerLayer*currentlayer + (i*self.height)*bytesPerNumber, bytesPerColumn)
            #pipe the data for the whole column over to the C++ program
            proc.stdin.write(RedBuffer)

        print("Piping layer 2 -> C++")
        print(time.ctime(time.time()))
        currentlayer += 1        

        #comments the same as the previous loops
        for i in range(self.width):
            for j in range(self.height):
                currentindex = bytesPerLayer*currentlayer + (j+i*self.height)*bytesPerNumber 
                pixelData1 = layers[1].dataProvider().identify(QgsPoint(self.AOI.xMinimum()+i*self.deltaX, self.AOI.yMinimum()+j*self.deltaY),QgsRaster.IdentifyFormatValue)
                RedBytes[ currentindex: currentindex + bytesPerNumber] = struct.pack('d',pixelData1.results()[1])
            RedBuffer = buffer(RedBytes, bytesPerLayer*currentlayer + (i*self.height)*bytesPerNumber, bytesPerColumn)
            proc.stdin.write(RedBuffer)

        print("Data piped")            
        print(time.ctime(time.time()))

        starttime = datetime.datetime.now()
        print("Getting Status from C++")
        for i in range(self.width-6):
                returnvalues = proc.stdout.read(4)
                a = buffer(returnvalues)
                b = struct.unpack_from('i', a)
                currenttime = datetime.datetime.now()
                deltatime = (currenttime-starttime).total_seconds()
                print "ETA for processing completion " + str( ((self.width + 0.0) / (b[0] + 0.0) - 1.0)*deltatime) + " Seconds"

        #receive the data and process it here                 

        print("Reading results back from C++")
        for i in range(self.width):
            returnvalues = proc.stdout.read(bytesPerColumn)
            a = buffer(returnvalues)
            b = struct.unpack_from(str(self.height)+'d', a)
            print str(b) + " " + str(i)

我收到以下错误消息:

  

msvcrt.setmode(sys.stdout.fileno(),os.O_BINARY)   AttributeError:writeOut实例没有属性' fileno'

上次我在这个项目中遇到stdin / stdout错误时,问题出在popen语句中。 popen要求我在从GUI代码调用它时管道所有三个std流。由于这与std流有关,并且代码在控制台上的PyDev中工作,我假设它现在是与GUI代码相关的问题。

我想知道从GUI代码或任何其他可以解决错误问题的想法中将std流设置为二进制模式的正确方法。

更新 我找到了解决办法,但是如果有人有真正的解决办法,我会保留问题。 我找到了解决这个问题的方法。我刚刚从python中删除了试图将std流设置为二进制模式的代码,并将其作为第一件事发生在我的C ++代码中。当python代码调用popen行时,C ++进程将std流设置为二进制模式。我仍然想知道Python是否有办法解决这个错误

0 个答案:

没有答案