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));
}
Related
I am writing a custom PAM module.
I have written a shared object (.so) file as required for Linux-PAM. What this .so file does, is call embedded Python to open up my facial recognition and , depending on the outcome, will return PAM_SUCCESS or PAM_AUTH_ERR
In the /etc/pam.d/sudo file I have told PAM that the file resides in (/home/berns/2020-ca326-cberns-fileencryption-with-opencv/PAM/pam_authnew.so). This is okay as , when sudo is typed, I can see my own personal error statement being printed saying it could not load the Python file.
The issue I have is, the facial recognition code resides in a total different directory from where the .so file resides. (../code/facial). I have used a chdir command in my C code, but it does'nt seem to change the directory back to where the Python facial files reside to provide success or not.
Is there something I'm missing ?
C code given below:
#define PAM_SM_AUTH
#define PAM_SM_ACCOUNT
#define PAM_SM_SESSION
#define GetCurrentDir getcwd
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <security/pam_appl.h>
#include <security/pam_modules.h>
#include </usr/include/python3.6m/Python.h>
int main(int argc, char** argv){
}
PAM_EXTERN int pam_sm_authenticate( pam_handle_t *pamh, int flags,int argc, const char **argv ){
char *result;
chdir("../code/facial"); // this changes it to the correct directory to execute
//dlopen("/usr/lib/x86_64-linux-gnu/libpython3.6m.so",RTLD_LAZY | RTLD_GLOBAL);
Py_Initialize(); // Starts python interpreter
PyRun_SimpleString("import os\nimport sys\nsys.path.append(os.getcwd())"); // lets python know where we are
PyObject *mymod, *func1, *ret1;
mymod = PyImport_ImportModule("pam_detect"); // This is the .py
if (mymod != NULL){ // check if the file file was loaded
func1 = PyObject_GetAttrString(mymod, "detect"); // hel is the function name in the file you declared earlier
ret1 = PyObject_CallObject(func1, NULL); // Null because the function doesnt take an argument.
result = PyUnicode_AsUTF8(ret1);
//printf("%s\n", result);
if (strcmp(result, "success") == 0){
Py_Finalize();
return PAM_SUCCESS;
}
else{
Py_Finalize();
return PAM_AUTH_ERR;
}
}
else{
printf("Error: can't find file!\n");
}
Py_Finalize();
return 0;
}
Error response from the terminal below
Is this due to child processes not changing the directories outside of their own running space ?
Also worth noting if I compile the C code WITHOUT making it a .so , I can load up the Python files perfectly and recognise my face.
I try to use a c++-class for socket communication in Python. Therefore, I created a class that uses nngpp. When importing the swigged file to python, I get the ImportError: undefined symbol: nng_msg_insert. The definition of the class is:
/* commclass.h */
#include <nngpp/nngpp.h>
#include <nngpp/protocol/req0.h>
#include <nngpp/protocol/rep0.h>
#include <nngpp/msg_body.h>
#include <nngpp/msg_header.h>
#include <nngpp/msg.h>
#include <nngpp/socket.h>
#include <nngpp/view.h>
#include <string>
#include <nlohmann/json.hpp>
//#include <thread>
#include <iostream>
#include <cstdio>
#include "/usr/local/include/nng/nng.h"
//#include <memory>
#include <chrono>
using json = nlohmann::json;
class CommIF
{
private:
nng::socket socket;
nng::msg message;
int msg_size;
public:
CommIF(const std::string option, std::string ipToListen, std::string ipToDial)
{
message = nng::make_msg(0);
if (option.compare("rep") == 0)
{
socket = std::move(nng::rep::v0::open());
}
else if (option.compare("req") == 0)
{
socket = std::move(nng::req::v0::open());
}
else
{
printf("EXCEPTION");
}
socket.listen(ipToListen.c_str());
bool connected = false;
while (connected == false)
{
try
{
socket.dial(ipToDial.c_str());
connected = true;
std::cout << "successfully connected\n";
}
catch (const nng::exception &e)
{
std::cerr << e.what() << "; retry in 1 s" << '\n';
//std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
msg_size = 0;
}
};
The interface file for swig is:
/* commclass.i */
%module commclass
%{
#include "src/commclass.h"
%}
%include "src/commclass.h"
I then start with the command python3 build_commclass.py build_ext --inplace the build process. The file build_commclass.py is the following
from distutils.core import setup, Extension
import os
name = "commclass"
version = "0.0.1"
os.environ["CC"] = "g++"
setup(name = name, version = version, ext_modules = [Extension(
name = '_commclass',
sources = ["commclass.i"],#"src/commclass.h"],
include_dirs = ['src'],#'/home/user1/Documents/extLibs','/usr/local/include'],
swig_opts = ["-c++", "-modern"]
)])
When I now import the the class to python, I get the error mentioned above. I searched a lot on google and stackoverflow and I am quite sure this is a linker issue. I also tried a lot of different things with the compiler and linker options of distutils.core, but I didn't find a solution.
Edit 1:
I now changed the interface file as following
/* commclass.i */
/* module*/
%module commclass
%{
#include "/usr/local/include/nng/nng.h"
#include "src/nngpp/nngpp.h"
#include "src/nngpp/protocol/req0.h"
#include "src/nngpp/protocol/rep0.h"
#include "src/nngpp/socket.h"
#include "src/nngpp/msg.h"
#include "src/nngpp/aio.h"
#include "src/nngpp/aio_view.h"
#include "src/nngpp/msg_body.h"
#include "src/nngpp/msg_header.h"
#include "src/commclass.h"
%}
%include "/usr/local/include/nng/nng.h"
%include "src/commclass.h"
I now get the same error when importing in python, but the undefined symbol changed. It is now nng_aio_set_iov. Both nng_msg_insert and nng_aio_set_iov are defined in the file nng.h which I have now included. I am confused now.
SWIG only generates interfaces for definitions that are directly specified by %include by default. nng_msg_insert is not defined in src/commclass.h. You need additional %include statements to bring in the definition.
Note you can change the default to recurse into all #include statements with the -includeall SWIG flag, but you generally don't want the entire <iostream>, <cstdio>, <string>, etc. interfaces to be wrapped and it likely won't work without a lot of additional effort.
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.?
I am trying to read some registers in hardware (FPGA) using Python.
I already have a C code to read the registers and it works fine. I want to use them in python using ctypes.
rdaxi.c
#include <fcntl.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#define NF10_IOCTL_CMD_READ_STAT (SIOCDEVPRIVATE+0)
#define NF10_IOCTL_CMD_WRITE_REG (SIOCDEVPRIVATE+1)
#define NF10_IOCTL_CMD_READ_REG (SIOCDEVPRIVATE+2)
int main(int argc, char* argv[]){
int f;
uint64_t v;
uint64_t addr;
if(argc < 2){
printf("usage: rdaxi reg_addr(in hex)\n\n");
return 0;
}
else{
sscanf(argv[1], "%llx", &addr);
}
//----------------------------------------------------
//-- open nf10 file descriptor
//----------------------------------------------------
f = open("/dev/nf10", O_RDWR);
if(f < 0){
perror("/dev/nf10");
return 0;
}
printf("\n");
v = addr;
if(ioctl(f, NF10_IOCTL_CMD_READ_REG, &v) < 0){
perror("nf10 ioctl failed");
return 0;
}
// upper 32bits contain the address and are masked away here
// lower 32bits contain the data
v &= 0xffffffff;
printf("AXI reg 0x%llx=0x%llx\n", addr, v);
printf("\n");
close(f);
return 0;
}
After comilation and getting the executable, I just do the following to get my result
./rdaxi 0x5a000008
AXI reg 0x5a000008 = 2
I want to do the same thing using Python.I came to know that I have to use Ctypes. Then I created shared library (.so) for my c file.The following is the python code i wrote. I am a beginner in python, so pardon me for my errors. I get a segmentation fault. How can I solve this and read the registers.
rdaxi.py
#!/usr/bin/env python
# For creating shared library
# gcc -c -Wall -fPIC rdaxi.c
# gcc -shared -o librdaxi.so rdaxi.o
import os
import sys
from ctypes import *
print "opening device descriptor"
nf = os.open( "/dev/nf10", os.O_RDWR )
print "loading the .so file"
librdaxi=cdll.LoadLibrary('/root/Desktop/apps/librdaxi.so')
librdaxi.main(nf,0x5b000008)
For more information about my application. Please see below.
reading registers in hw using python
thanks
main() takes two parameters, argc and argv, but you are passing it a single parameter which is your address.
Here's an example of how you might call it:
librdaxi.main.argtypes = [c_int,POINTER(c_char_p)]
argv=(c_char_p*2)()
argv[0]='rdaxi'
argv[1]='0x5a000008'
librdaxi.main(2,argv)
I've been messing around with the Python/C API and have this code:
#include <Python.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
//Initialize Python
Py_Initialize();
//Run file
FILE *fp = fopen("Test.py", "r");
PyRun_SimpleFile(fp,"Test.py");
fclose(fp);
//Run Python code
PyRun_SimpleString("print(__NAME__)");
PyRun_SimpleString("print(__DESC__)");
PyRun_SimpleString("print(__SKIN__)");
PyRun_SimpleString("onEnable()");
//Finalize Python
Py_Finalize();
return EXIT_SUCCESS;
}
Test.py contains this:
__NAME__ = "Frank"
__DESC__ = "I am a test script"
__SKIN__ = "random image"
def onEnable():
print("In Func")
As you would expect, compiling and running the c program results in this:
Frank
I am a test script
random image
In Func
However, I need a way to get the python strings from interpreter, stick them in C strings and then print them, rather than using PyRun_SimpleString("print(blah)").
For example:
char *__NAME__;
__NAME__ = Py_GetObject("__NAME__")
Is this possible?
Thanks for your help.
You need to use PyString_AsString. I think it goes something like this:
PyObject* module = PyImport_AddModule("__main__");
PyObject* o = PyObject_GetAttrString(module , "__NAME__");
if (PyString_Check(o))
{
const char* name = PyString_AsString(o);
// don't delete or modify "name"!
}
Py_DECREF(o);