I am wrote sample C++ application. Now I am going communicate with Python through Swig.
What I did
Generated interface file for my function
classify.i
%module example
%{
#include "Facdetect.h"
%}
%include "typemaps.i"
%include "cstring.i"
%include "cdata.i"
%include <std_string.i>
%apply unsigned char *{unsigned char *x};
%apply double *INOUT{double *y};
%include "Facdetect.h"
Facdetect.h
#include <iostream>
class facedetect
{
public:
void display(unsigned char *x,double *y);
};
sample.cpp
#include <cstdlib>
#include "Facdetect.h"
using namespace std;
void facedetect::display( unsigned char *x,double *y)
{
cv::Mat in(512,512,CV_8UC3,x);
cv::Mat res=imdecode(in,1);
cv::cvtColor(res,res,cv::COLOR_RGB2GRAY);
std::vector<uchar> buff;
cv::imencode(".jpg",res,buff);
int k=0;
std::cout<<" buffer size "<<buff.size()<<std::endl;
for(int j=0;j<10;j++)
{
y[k++]=j;
}
}
sample.py
import os
import io
import sys
import time
import example
from PIL import Image
import struct
from array import array
def readimage(path):
count = os.stat(path).st_size / 2
with open(path, "rb") as f:
return bytearray(f.read())
bytes = readimage("sample.jpg")
print len(bytes)
c=example.facedetect()
ret = array(10)
ret=c.display(bytes,ret)
print ret
I had successfully passed byte array from Python to C++.
Now i am passing double array values into python fro C++.
I did not get double array values in python from C++.
What I need:
How to get double array values from C++ to python.?
Is any typemaps i missed for generating swig wrapper.?
Related
I'm trying to make a basic csv parser in c++ for a particular csv schema, and I'm trying to wrap the function for Python, but I keep getting a "StdVectorTraits not found" warning after wrapper generation. The wrapper is still able to be compiled using g++, but when I try to import the underlying shared object using the object.py script, I get "ImportError: undefined symbol: _Z8myVectorRNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE"
This is the swig interface file:
%module parser;
%include "/usr/share/swig4.0/std/std_vector.i";
%include "/usr/share/swig4.0/std/std_iostream.i";
%include "/usr/share/swig4.0/std/std_sstream.i";
%include "/usr/share/swig4.0/std/std_string.i";
%include "/usr/share/swig4.0/std/std_basic_string.i";
%{
#include <vector>
#include <fstream>
#include <sstream>
#include <iostream>
std::vector<std::vector<double>> myVector(std::string&);
%}
%template(doubleVector) std::vector<double>;
%template(doubleVecVector) std::vector<std::vector<double>>;
std::vector<std::vector<double>> myVector(std::string& path)
{
std::ifstream file;
std::string read;
std::vector<std::vector<double>> data;
file.open(path);
for (int i = 0; i < 21; i++)
{
std::getline(file, read);
}
for (int i = 0; i < 32; i++)
{
std::vector<double> line;
std::getline(file, read);
std::stringstream ss(read);
for (int j = 0; j < 48; j++)
{
std::getline(ss, read, ',');
line.push_back(std::stof(read));
}
data.push_back(line);
}
file.close();
return data;
}
Error:
---------------------------------------------------------------------------
ImportError Traceback (most recent call last)
/home/../test.ipynb Cell 1 in <cell line: 1>()
----> 1 import parser
File ~/../parser.py:15, in <module>
13 from . import _parser
14 else:
---> 15 import _parser
17 try:
18 import builtins as __builtin__
ImportError: /home/../_parser.so: undefined symbol: _Z8myVectorRNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
The function definition should be between %{ and %}. Everything between %{/%} is included directly in the generated wrapper. The function prototype should be at the end of the file after the %template declarations to direct SWIG to generate a wrapper for that function.
Since the function body is in the wrong place it isn't defined hence the undefined symbol error.
Stripped down example:
test.i
%module test
%{
#include <vector>
std::vector<std::vector<double>> myVector()
{
return {{1.0,1.5},{2.0,2.5}};
}
%}
%include <std_vector.i>
%template(doubleVector) std::vector<double>;
%template(doubleVecVector) std::vector<std::vector<double>>;
std::vector<std::vector<double>> myVector();
Demo:
>>> import test
>>> test.myVector()
((1.0, 1.5), (2.0, 2.5))
I have been trying to get this to work for a while now. I am trying to wrap a LOT of c++ classes in swig, but I can't even get the first one to work. The error is at the bottom. Here is my interface file, setup.py, and class file.
Interface
//This file is automatically generated from "build_swig_files.py
//Makes changes to build_swig_files.py to edit jcm.i
%module jcm
%{
#include "jtag/GenericJTAGDevice.h"
typedef unsigned int u32;
%}
class GenericJTAGDevice {
public:
virtual ~GenericJTAGDevice();
GenericJTAGDevice(int irLength, int idCode);
unsigned int getIrLength();
unsigned int getIdCode();
private:
unsigned int idCode;
unsigned int irLength;
};
typedef unsigned int u32;
%include <std_string.i>
using std::string;
%include "cpointer.i"
%pointer_functions(u32, u32p);
%include "carrays.i"
%array_class(u32, u32a);
%include "std_vector.i"
namespace std {
%template(IntVector) vector<int>;
}
setup.py
from distutils.core import setup, Extension
jcm_sources = [
"jcm.i",
"/root/git/jcm/jcm_source/base/src/jtag/GenericJTAGDevice.cpp"
]
jcm_module = Extension('_jcm',
sources=jcm_sources,
swig_opts=[ '-I/root/git/jcm/jcm_source/base/include',
'-I/root/git/jcm/jcm_source/base/include/jtag',
'-I/root/git/jcm/jcm_source/base/include/util',
'-I/root/git/jcm/jcm_source/base/include/xilinx',
'-c++'],
include_dirs=[ '/root/git/jcm/jcm_source/base/include',
'/root/git/jcm/jcm_source/base/include/jtag',
'/root/git/jcm/jcm_source/base/include/util',
'/root/git/jcm/jcm_source/base/include/xilinx'],
libraries=['supc++'])
setup (name = 'jcm', version = '0.3', author = 'BYUCCL', ext_modules = [jcm_module], py_modules = ["jcm"])
Class Header
#ifndef GENERIC_JTAG_DEVICE_H
#define GENERIC_JTAG_DEVICE_H
#include <string>
#include <vector>
//#include "JTAGDevice.h"
using namespace std;
/**
* #brief Basic implementation of a JTAGDevice
*
* \class GenericJTAGDevice
*
**/
class GenericJTAGDevice {
public:
virtual ~GenericJTAGDevice();
GenericJTAGDevice(int irLength, int idCode);
unsigned int getIrLength();
unsigned int getIdCode();
private:
unsigned int idCode;
unsigned int irLength;
};
#endif // GENERIC_JTAG_DEVICE_H
Here is the error:
>>> import sys
>>> sys.path.insert(0, '/root/git/JCM/jcm_source/python/swig')
>>> import jcm
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/root/git/jcm/jcm_source/python/swig/jcm.py", line 64, in <module>
class GenericJTAGDevice(object):
File "/root/git/jcm/jcm_source/python/swig/jcm.py", line 67, in GenericJTAGDevice
__swig_destroy__ = _jcm.delete_GenericJTAGDevice
AttributeError: module '_jcm' has no attribute 'delete_GenericJTAGDevice'
I have tried a couple variations in the interface file, such as not having the whole class definition and just doing %include GenericJTAGDevice.h. I have a feeling it has to do with the virtual destructor, but I don't know how to fix that because I need the destructor.
Edit: I tried with another class and it did the same thing. So perhaps I am understanding the interface file wrong.
Edit: All I am running is python3 setup.py build
So I saw the answer in the link below before but didn't understand what it was saying. Basically, my process to build swig didn't include making a new _jcm.so. So pretty much the first time I ran it was it, and after that all the changes I made to the .i or the code or setup.py didn't mean anything because the _jcm.so wasn't being rewritten. In my case, I run a "make clean" from my make file and it deletes the _jcm.so. After that I build the _jcm.so again, and then run setup.py.
Simple, but hard to find.
http://swig.10945.n7.nabble.com/Req-module-object-has-no-attribute-delete-TSP-CA-td2271.html
I need to read an image (with OpenCV) in Python, pipe it to a C++ program and then pipe it back to Python.
This is my code so far:
C++
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <cv.h>
#include <highgui.h>
#include <cstdio>
#include <sys/stat.h>
using namespace std;
using namespace cv;
int main(int argc, char *argv[]) {
const char *fifo_name = "fifo";
mknod(fifo_name, S_IFIFO | 0666, 0);
ifstream f(fifo_name);
string line;
getline(f, line);
auto data_size = stoi(line);
char *buf = new char[data_size];
f.read(buf, data_size);
Mat matimg;
matimg = imdecode(Mat(1, data_size, CV_8UC1, buf), CV_LOAD_IMAGE_UNCHANGED);
imshow("display", matimg);
waitKey(0);
return 0;
}
Python
import os
import cv2
fifo_name = 'fifo'
def main():
data = cv2.imread('testimage.jpg').tobytes()
try:
os.mkfifo(fifo_name)
except FileExistsError:
pass
with open(fifo_name, 'wb') as f:
f.write('{}\n'.format(len(data)).encode())
f.write(data)
if __name__ == '__main__':
main()
An exception is thrown when C++ tries to print to image. I have debugged the code and buf is filled, but matimg is empty.
In the code, the C++ reader calls mknod, whereas it should just open an existing named pipe created by the Python writer.
If the pipe doesn't exists when the reader tries to open it, it can either fail or keep re-trying to open the named pipe with a timeout. E.g.:
const char *fifo_name = "fifo";
std::ifstream f;
for(;;) { // Wait till the named pipe is available.
f.open(fifo_name, std::ios_base::in);
if(f.is_open())
break;
std::this_thread::sleep_for(std::chrono::seconds(3));
}
I'm using swig to wrap a c++ library, it needs to get image data as char*. I can read the image in python. But how can i trans it to c++?
I konw I might need to use typemap. I tried several ways, but I always get a picture with only stripes.
This is my interface file:
/* np2char */
%module np2char
%{
#define SWIG_FILE_WITH_INIT
#include <opencv2/opencv.hpp>
using namespace cv;
%}
%inline %{
typedef char* Image_Data_Type;
typedef int Image_Width_Type;
typedef int Image_Height_Type;
struct Image_Info {
Image_Data_Type imageData;
Image_Width_Type imageWidth;
Image_Height_Type imageHeight;
};
int Imageshow(Image_Info ImageInfo) {
Mat img(ImageInfo.imageHeight, ImageInfo.imageWidth, CV_8UC3, ImageInfo.imageData);
imshow("img_in_cpp", img);
waitKey(0);
destroyAllWindows();
return 0;
}
%}
This is my setup.py:
"""
setup.py
"""
from distutils.core import setup,Extension
module1 = Extension('_np2char',
sources=['np2char_wrap.cxx'],
include_dirs=['include'],
libraries = ["opencv_world342"],
library_dirs=["lib"],
)
setup(name = "np2char",
version = "1.0",
description = 'This package is used to trans ndarray to char*',
ext_modules = [module1],
py_modules=['np2char'])
and this is my python file:
import np2char
import cv2
img1 = cv2.imread("1.jpg")
img_info = np2char.Image_Info()
img_info.imageData = img1.data
img_info.imageWidth = img1.shape[1]
img_info.imageHeight = img1.shape[0]
np2char.Imageshow(img_info)
I have tried
%typemap(in) Image_Data_Type{
$1 = reinterpret_cast<char*>(PyLong_AsLongLong($input));
}
, and in python side
img_info.imageData=img1.ctypes.data
But still I got only stripes. It seems that imagedata is copied to other places in memory. In the process, it was truncated by '\0'.
haha, I figured it out myself.
In SWIG Documentation 5.5.2,
SWIG assumes that all members of type char * have been dynamically allocated using malloc() and that they are NULL-terminated ASCII strings.
If this behavior differs from what you need in your applications, the SWIG "memberin" typemap can be used to change it.
So, what I need is "typemap(memberin)":
%typemap(in) Image_Data_Type{
$1 = reinterpret_cast<Image_Data_Type>(PyLong_AsLongLong($input));
}
%typemap(memberin) Image_Data_Type{
$1 = $input;
}
%typemap(out) Image_Data_Type{
$result = PyLong_FromLongLong(reinterpret_cast<__int64>($1));
}
It's a bit ugly using integer to transfer pointer. Is there a better way?
Hello and thanks for your help in advance !
I am writing a python wrapper (SWIG 2.0 + Python 2.7) for a C++ code. The C++ code has typedef which I need to access in python wrapper. Unfortunately, I am getting following error when executing my Python code:
tag = CNInt32(0)
NameError: global name 'CNInt32' is not defined
I looked into SWIG documentation section 5.3.5 which explains size_t as typedef but I could not get that working too.
Following is simpler code to reproduce the error:
C++ header:
#ifndef __EXAMPLE_H__
#define __EXAMPLE_H__
/* File: example.h */
#include <stdio.h>
#if defined(API_EXPORT)
#define APIEXPORT __declspec(dllexport)
#else
#define APIEXPORT __declspec(dllimport)
#endif
typedef int CNInt32;
class APIEXPORT ExampleClass {
public:
ExampleClass();
~ExampleClass();
void printFunction (int value);
void updateInt (CNInt32& var);
};
#endif //__EXAMPLE_H__
C++ Source:
/* File : example.cpp */
#include "example.h"
#include <iostream>
using namespace std;
/* I'm a file containing use of typedef variables */
ExampleClass::ExampleClass() {
}
ExampleClass::~ExampleClass() {
}
void ExampleClass::printFunction (int value) {
cout << "Value = "<< value << endl;
}
void ExampleClass::updateInt(CNInt32& var) {
var = 10;
}
Interface file:
/* File : example.i */
%module example
typedef int CNInt32;
%{
#include "example.h"
%}
%include <windows.i>
%include "example.h"
Python Code:
# file: runme.py
from example import *
# Try to set the values of some typedef variables
exampleObj = ExampleClass()
exampleObj.printFunction (20)
var = CNInt32(5)
exampleObj.updateInt (var)
Thanks again for your help.
Santosh
I got it working. I had to use typemaps in the interface file, see below:
- Thanks a lot to "David Froger" on Swig mailing lists.
- Also, thanks to doctorlove for initial hints.
%include typemaps.i
%apply CNInt32& INOUT { CNInt32& };
And then in python file:
var = 5 # Note: old code problematic line: var = CNInt32(5)
print "Python value = ",var
var = exampleObj.updateInt (var) # Note: 1. updated values returned automatically by wrapper function.
# 2. Multiple pass by reference also work.
# 3. It also works if your c++ function is returning some value.
print "Python Updated value var = ",var
Thanks again !
Santosh