我一直致力于一个项目,该项目在用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是否有办法解决这个错误