Serialize array data from C code, deserialize in Python - python

I need to store dense array data (3D arrays) from C code and then to read them into NumPy arrays (in another application). The data is around 100 kbytes of float values, C array as a pointer to the data. I am looking for a solution that does not require any external dependencies and can be implemented with the least effort.
What would be a good solution for that?
Thanks.

I've done some serialization for arm devices and network and I'would be happy to share my experience since you prefer binary serialization.
I am using unions to serialize.Lets assume that you have a struct that holds some element, data and pointers and this holds data for a family member :
struct fam_member
{
char name [ MAX_NAME_LEN + 1 ];
int height;
age_bracket_t age_bracket;
fam_member_t* mother;
fam_member_t* father;
}fam_member_t;
Age bracket is an enum:
typedef enum age_bracket
{
under_18 = 0 , from_18_to_25 = 1 , from_26_to_40 = 2 , over_40 = 3
}age_bracket_t;
The main problem and the most common mistake is struct padding and not taking this to serious.Here is a good start if someone is not familiar with the issue.
My simple solution is stream data down byte to byte (or bit to bit), do what you need to do with the serialized data (i.e. send them over a socket) and deserialize in the end.
I define a Union like this:
typedef union serialized_struct
{
fam_member_t family_member;
unsigned char data[ (MAX_NAME_LEN + 1 ) + (sizeof(int)*3) ];
}serialized_struct_t;
(A few think about union here)
The purpose of union is to save memory by using the same memory region for storing different objects at different times.In this example this will help us and actually serialize the family object struct for free.
Here is a function that serializes an array of family members (if you can do an area, single will be a piece of cake.That's why I choose an array here).
int serialize_array(fam_member_t* people , char* message , int elements)
{
if((people == NULL ) || (message == NULL) || (elements < 1))
{
return -1;
}
int size = sizeof(fam_member_t);
int i;
for(i=0 ; i < elements ; i++)
{
serialized_struct_t x;
memcpy((x.family_member.name) , people[i].name , MAX_NAME_LEN);
x.family_member.age_bracket = people[i].age_bracket;
x.family_member.height = people[i].age_bracket
x.family_member.mother = people[i].mother;
x.family_member.father = people[i].father;
memcpy ( (message + (size * i)) , x.data , size );
}
return 0;
}
Here we initiate every data of every member inside the struct which lies in the union.Message holds serialized data.This is the deserialized function which will do the reverse
int desirialize_array(fam_member_t* people , char* message , int elements)
{
if((people == NULL ) || (message == NULL) || (elements < 1))
{
return -1;
}
int size = sizeof(fam_member_t);
serialized_struct_t y;
int i;
for (i =0 ; i < elements ; i ++ )
{
memcpy ( y.data , (message + (size * i)) , size );
memcpy ( people[i].name , y.family_member.name , MAX_NAME_LEN);
people[i].age_bracket = y.family_member.age_bracket;
people[i].height = y.family_member.height;
people[i].mother = y.family_member.mother;
people[i].father = y.family_member.father;
}
return 0;
}
This is serialize and deserialize in c example.For your case where you need to deserialize this in python I think it will be easy if you figured out which will be the mean of serialization.JSON that #Alexander Tolkachev said for example could be a solution.
I hope this simplified example helps you.

Related

C++ byte array (struct) interpreted by Python

I am trying to pass a C++ struct from my arduino to my raspberry pi. I have a struct that looks like this:
struct node_status
{
char *node_type = "incubator";
char *sub_type; // set the type of incubator
int sub_type_id;
bool sleep = false; // set to sleep
int check_in_time = 1000; // set check in time
bool LOCK = false; // set if admin control is true/false
} nodeStatus;
I tried using the python module named struct
from struct import *
print("Rcvd Node Status msg from 0{:o}".format(header.from_node))
print("node_type: {}".format(unpack("10s",payload[0]))) #node_type
node_type = unpack("10s",payload[0])
print("sub_type: {}".format(unpack("10s",payload[1]), header.from_node)) #sub_type
sub_type = unpack("10s",payload[1])
print("sub_type_id: {}".format(unpack("b",payload[2])))
sub_type_id = unpack("b",payload[2])
print("sleep: {}".format(unpack("?",payload)[3])) #sleep
sleep = unpack("?",payload[3])
print("check_in_time: {}".format(unpack("l",payload[4]))) #check_in_time
check_in_time = unpack("l",payload[4])
print("Lock: {}".format(unpack("?",payload[5]))) #LOCK
Lock = unpack("?",payload[5])
but I am not having much luck. I was even looking at just using ctypes module but seem to not be going anywhere..
from ctypes import *
class interpret_nodes_status(Structure):
_fields_ = [('node_type',c_char_p),
('sub_type',c_char_p),
('sub_type_id',c_int),
('sleep',c_bool),
(check_in_time',c_int),
('LOCK',c_bool)]
nodestatus = translate_nodes_status(payload)
but that just gives me an error
TypeError: bytes or integer address expected instead of bytearray instance
What can I do? WHERE am I going wrong with this?
EDIT:
I am using the RF24Mesh Library from
https://github.com/nRF24/RF24Mesh
The way I send the message is this?
RF24NetworkHeader header();
if (!mesh.write(&nodeStatus, /*type*/ 126, sizeof(nodeStatus), /*to node*/ 000))
{ // Send the data
if ( !mesh.checkConnection() )
{
Serial.println("Renewing Address");
mesh.renewAddress();
}
}
else
{
Serial.println("node status msg Sent");
return;
}
}
Your C program is just sending the struct, but the struct doesn't contain any of the string data. It only includes pointers (addresses) which are not usable by any other process (different address spaces).
You would need to determine a way to send all the required data, which would likely mean sending the length of each string and its data.
One way to do that would be to use a maximum length and just store the strings in your struct:
struct node_status
{
char node_type[48];
char sub_type[48]; // set the type of incubator
int sub_type_id;
bool sleep = false; // set to sleep
int check_in_time = 1000; // set check in time
bool LOCK = false; // set if admin control is true/false
} nodeStatus;
You would then need to copy strings into those buffers instead of assigning them, and check for buffer overflow. If the strings are ever entered by users, this has security implications.
Another approach is to pack the data into a single block just when you send it.
You could use multiple writes, as well, but I don't know this mesh library or how you would set the type parameter to do that. Using a buffer is something like:
// be sure to check for null on your strings, too.
int lennodetype = strlen(nodeStatus.node_type);
int lensubtype = strlen(nodeStatus.sub_type);
int bufsize = sizeof(nodeStatus) + lennodetype + lensubtype;
byte* buffer = new byte[bufsize];
int offset = 0;
memcpy(buffer+offset, &lennodetype, sizeof(int));
offset += sizeof(int);
memcpy(buffer+offset, nodeStatus.node_type, lennodetype * sizeof(char));
offset += lennodetype * sizeof(char);
memcpy(buffer+offset, &lensubtype, sizeof(int));
offset += sizeof(int);
memcpy(buffer+offset, nodeStatus.sub_type, lensubtype * sizeof(char));
offset += lensubtype * sizeof(char);
// this still copies the pointers, which aren't needed, but simplifies the code
// and 8 unused bytes shouldn't matter too much. You could adjust this line to
// eliminate it if you wanted.
memcpy(buffer+offset, &nodeStatus, sizeof(nodeStatus));
if (!mesh.write(buffer,
/*type*/ 126,
bufsize,
/*to node*/ 000))
{ // Send the data
if ( !mesh.checkConnection() )
{
Serial.println("Renewing Address");
mesh.renewAddress();
}
}
else
{
Serial.println("node status msg Sent");
}
delete [] buffer;
Now that the data is actually SENT (a prerequisite for reading the data) the data you need should all be in the payload array. You will need to unpack it, but you can't just pass unpack a single byte, it needs the array:
len = struct.unpack("#4i", payload)
offset = 4
node_type = struct.unpack_from("{}s".format(len), payload, offset)
offset += len
len = struct.unpack_from("#4i", payload, offset)
offset += 4
sub_type = struct.unpack_from("{}s".format(len), payload, offset)
offset += len
...
I upvoted Garr Godfrey's answer as it is a good one indeed. However, it will increase the struct's size. This neither a good nor bad thing, however if for some reason you would like to keep the solution based on char* pointers instead of arrays (e.g. you don't know the maximum length of the strings), it can be achieved the following way (my code makes assumption of int's size being 4 bytes, little endian, bool's size=1bytes, char size=1byte):
//_Static_assert(sizeof(int)==4u, "Int size has to be 4 bytes");
//the above one is C11, the one below is C++:
//feel free to ifdef that if you need it
static_assert(sizeof(int)==4u, "Int size has to be 4 bytes");
struct node_status
{
char* node_type;
char* sub_type; // set the type of incubator
int sub_type_id;
bool sleep; // set to sleep
int check_in_time; // set check in time
bool LOCK; // set if admin control is true/false
};
size_t serialize_node_status(const struct node_status* st, char* buffer)
{
//this bases on the assumption buffer is large enough
//and string pointers are not null
size_t offset=0u;
size_t l = 0;
l = strlen(st->node_type)+1;
memcpy(buffer+offset, st->node_type, l);
offset += l;
l = strlen(st->sub_type)+1;
memcpy(buffer+offset, st->sub_type, l);
offset += l;
l = sizeof(st->sub_type_id);
memcpy(buffer+offset, &st->sub_type_id, l);
offset += l;
l = sizeof(st->sleep);
memcpy(buffer+offset, &st->sleep, l);
offset += l;
l = sizeof(st->check_in_time);
memcpy(buffer+offset, &st->check_in_time, l);
offset += l;
l = sizeof(st->LOCK);
memcpy(buffer+offset, &st->LOCK, l);
offset += l;
return offset;
// sending:
char buf[100] = {0}; //pick the needed size or allocate it dynamically
struct node_status nodeStatus = {"abcz", "x", 20, true, 999, false};
size_t serialized_bytes = serialize_node_status(&nodeStatus, buf);
mesh.write(buf, /*type*/ 126, serialized_bytes, /*to node*/ 000);
Side note: assigning string literals directly to char pointers is not valid C++.
So the string types either should be const char*, e.g. const char* node_type or the file should be compiled as C (where you can get away with it). Arduino often tends to have its own compilation options set, so it is likely to work due to compiler extension (or just inhibited warning). Thus, not being sure what exactly is going to be used, I wrote a C11-compatible version.
And then on Python's end:
INT_SIZE=4
class node_status:
def __init__(self,
nt: str,
st: str,
stid: int,
sl: bool,
cit: int,
lck: bool):
self.node_type = nt
self.sub_type = st
self.sub_type_id = stid
self.sleep = sl
self.check_in_time = cit
self.LOCK = lck
def __str__(self):
s=f'node_type={self.node_type} sub_type={self.sub_type}'
s+=f' sub_type_id={self.sub_type_id} sleep={self.sleep}'
s+=f' check_in_time={self.check_in_time} LOCK={self.LOCK}'
return s;
#classmethod
def from_bytes(cls, b: bytes):
offset = b.index(0x00)+1
nt = str(b[:offset], 'utf-8')
b=b[offset:]
offset = b.index(0x00)+1
st = str(b[:offset], 'utf-8')
b=b[offset:]
stid = int.from_bytes(b[:INT_SIZE], 'little')
b = b[INT_SIZE:]
sl = bool(b[0])
b = b[1:]
cit = int.from_bytes(b[:INT_SIZE], 'little')
b = b[INT_SIZE:]
lck = bool(b[0])
b = b[1:]
assert(len(b) == 0)
return cls(nt, st, stid, sl, cit, lck)
#and the deserialization goes like this:
fromMesh1 = bytes([0x61,0x62,0x63,0x0,0x78,0x79,0x7A,0x0,0x14,0x0,0x0,0x0,0x1,0xE7,0x3,0x0,0x0,0x1])
fromMesh2 = bytes([0x61,0x62,0x63,0x0,0x78,0x79,0x7A,0x0,0x14,0x0,0x0,0x0,0x1,0xE7,0x3,0x0,0x0,0x0])
fromMesh3 = bytes([0x61,0x62,0x63,0x7A,0x0,0x78,0x0,0x14,0x0,0x0,0x0,0x1,0xE7,0x3,0x0,0x0,0x0])
print(node_status.from_bytes(fromMesh1))
print(node_status.from_bytes(fromMesh2))
print(node_status.from_bytes(fromMesh3))
These are all good answers but not what was required. I suppose a more in depth knowledge of the RF24Mesh library was needed. I have been able to find the answer with the help of some RF24 pro's. Here is my solution:
I had to change the struct to specific sizes using char name[10] on the C++ arduino side.
struct node_status
{
char node_type[10] = "incubator";
char sub_type[10] = "chicken"; // set the type of incubator
int sub_type_id = 1;
bool sleep = false; // set to sleep
int check_in_time = 1000; // set check in time
bool LOCK = false; // set if admin control is true/false
} nodeStatus;
Unfortunately, it looks like read() returns the payload with a length of what you passed to the read() function. This is unintuitive and should be improved. Not to mention, the parameter specifying the length of the payload to return should be optional.
Until they get a fix for this, I will have to slice the payload to only the length that struct.pack() needs (which can be determined based on the format specifier string). So, basically
# get the max sized payload despite what was actually received
head, payload = network.read(144)
# unpack 30 bytes
(
node_type,
sub_type,
sub_type_id,
sleep,
check_in_time,
LOCK,
) = struct.unpack("<10s10si?i?", payload[:30])
I finally got it to work using this method. I want to be fair about giving the points and would like to have your opinion on who should get them that was closest to this method. Please comment below.

Possible solutions for returning structs as rvalues without heap allocations: use case neural networks

MNIST is the hello world of machine learning and I've practiced it with TensorFlow and with pure python and numpy.
For more practice I am trying to write it in C on my own with only the standard library because I am relatively new to C and it's a great way to learn.
It's taken three weeks, and a lot of SEGFAULTS but I get 81% accuracy. Not very good but it's for learning.
The most troubling stuff was of course malloc/free for the data in the matrix struct as below:
typedef struct matrix{
int rows, cols;
float *data;
} matrix;
The forward and backward passes have things like:
1) matrix dot product
2) matrix add
3) matrix subtract
4) activation function (sigmoid in this case)
To avoid memory leaks I pass in three structs like so:
void matrix_add(matrix *a, matrix *b, matrix *res);
If res requires a dimensions change from a previous layer, then I free it and do a new malloc like so:
void zero_out_data(matrix *res, int rows, int cols)
{
if (res->rows != rows || res->cols != cols)
{
if ((res->rows*res->cols) != (rows*cols))
{
free(res->data);
res->data = NULL;
free(res);
res = NULL;
res = malloc(sizeof(matrix));
// make_matrix will calloc the data based on rows*cols
// any other init stuff that could be needed
make_matrix(res, rows, cols);
}
res->rows = rows;
res->cols = cols;
}
else {
res->rows = rows;
res->cols = cols;
for (int i =0; i < (rows*cols); i++)
{
res->data[i] = 0.0;
}
}
}
Then I can use that like so:
void sigmoid(matrix *z, matrix *res)
{
zero_out_data(res, z->rows, z->cols);
for (int i = 0; i < (z->rows*z->cols); i++)
{
res->data[i] = 1.0/(1.0+exp(-z->data[i]));
}
}
This gets very messy because a single forward pass has the following:
/* forward pass */
for (int k=0; k < (network->num_layers-1); k++)
{
matrix_dot(network->weights[k], activation, dot);
matrix_add(dot, network->biases[k], zs[k]);
sigmoid(zs[k], activation);
sigmoid(zs[k], activations[k+1]);
}
/* end forward pass */
As you can imagine the backprop gets alot messier. I have to pre-create 8 different matrices, plus many more of those pointers to pointers of matrices like the activations and zs above, for the gradient descent.
What I would like to be able to do is return a matrix from a function like matrix_dot so that I can do:
sigmoid(matrix_add(matrix_dot(network->weights[k], activation), network->biases[k]));
That's kind of in the style of python/numpy.
Of course I can't return a local variable from a function because it's taken off the stack once the function returns.
If I return a pointer, then the above style will cause sever memory leaks.
Please note: I am not trying to write my own library/framework. I am simply trying to learn neural networks and coding in C. I have been a python developer for 7 years or so, and my C skills need improvement.
Memory leak in void zero_out_data(matrix *res, int rows, int cols)
matrix *res malloc out of the function and pass to zero_out_data. In zero_out_data, res is free and malloc again. If you want to change pointer res's value, then you need parameter like matrix **res.
If you want zero out data, no need malloc new matrix, just malloc the data part. I think your make_matrix function can malloc memory for data.
void zero_out_data(matrix *res, int rows, int col) {
if (res->data == NULL) {
make_matrix(res, rows, cols);
} else if (res->rows != rows || res->cols != cols) {
if ((res->rows*res->cols) != (rows*cols))
{
free(res->data);
res->data = NULL;
make_matrix(res, rows, cols);
}
}
res->rows = rows;
res->cols = cols;
for (int i =0; i < (rows*cols); i++)
{
res->data[i] = 0.0;
}
}
How to implement this: sigmoid(matrix_add(matrix_dot(network->weights[k], activation), network->biases[k])); ?
You can use static or global variables to implement what you want. This will not be thread safe and reentrant. Examples in below:
matrix *matrix_dot(matrix *in_a, matrix *in_b)
{
static matrix res = {0, 0, NULL}; // static variable
// calculate the res's cols and rows number
zero_out_data(&res, res_cols, res_rows); // malloc new data
// do some math.
return &res;
}
// matrix_add will be just like matrix_dot
// I was wrong about sigmod no need new matrix. sigmod can also do it like matrix_dot.
You can use global variable replace static variable.
If you want thread-safe or reentrant, then just use local variable, then you can do it like this.
matrix *matrix_dot(matrix *in_a, matrix *in_b, matrix *res)
{
zero_out_data(res, xxx, xxx);
// do some math
return res;
}
// matrix_add will be the same.
// define local variables.
matrix add_res, dot_res, sig_res;
add_res->data = NULL;
dot_res->data = NULL;
sig_res->data = NULL;
sigmod(matrix_add(matrix_dot(network->weights[k], activation, &dot_res), network->biases[k], &add_res), &sig_res)
// Now remember to free data in matrix
free(add_res->data);
free(dot_res->data);
free(sig_res->data);

How to define structure with dynamic length array inside in ctypes?

I want to use a dll function which returns AP ssid list in Python, But it takes a preallocated struct with dyamic length array inside. I don't know how to define such a structure, without knowing the returned array length in advance.
Below is how the definition looks like in the C# demo; specifically the SSID byte array length in this struct varies.
public extern static bool D300SysUI_WiFiGetAroundSsidStatus(IntPtr SSIDList, int nMaxCount);
public struct SSIDLISTNET
{
public uint ATIMWindow;
public D300SysUI.NDIS_802_11_AUTHENTICATION_MODE AuthenticationMode;
public uint BeaconPeriod;
public uint DSConfig;
public uint DwellTime;
public uint HopPattern;
public uint HopSet;
public D300SysUI.NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode;
public byte[] MacAddress;
public D300SysUI.NDIS_802_11_NETWORK_TYPE NetworkTypeInUse;
public uint NumberOfItems;
public uint Privacy;
public byte[] Reserved;
public int Rssi;
public byte[] Ssid;
public uint SsidLength;
public byte[] SupportedRates;
}
Do I need to create_string_buffer long enough by estimation ? And loop through the returned buffer, byte by byte and assmebly the bytes into element by size?
If that is the right way, how do I determine the end of the dymamic arrays ? (please pardon my ignorance, I am new to ctypes/c++)
PS: Example from the C# SDK
//D300SysUI.SSIDLIST[] items= new D300SysUI.SSIDLIST[30];
//IntPtr[] ptArray = new IntPtr[1];
//ptArray[0] = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(D300SysUI.SSIDLIST)) * 30);
//bool b = D300SysUI.D300SysUI_WiFiGetAroundSsidStatus(ptArray[0], 30);
//string message = "";
//string mac = "";
//if (b)
//{
// items[0] = (D300SysUI.SSIDLIST)Marshal.PtrToStructure((IntPtr)((UInt32)ptArray[0]), typeof(D300SysUI.SSIDLIST));
// for (int i =0;i<6;i++)
// {
// mac += String.Format("{0:X2} ", items[0].MacAddress[i]);
// }
// message += string.Format("AP:{0},MAC:{1},dBm:{2} \r\n",Encoding.GetEncoding("ASCII").GetString(items[0].Ssid,0,(int)(items[0].SsidLength)),mac,items[0].Rssi);
// for (int j = 1; j < items[0].NumberOfItems; j++)
// {
// items[j] = (D300SysUI.SSIDLIST)Marshal.PtrToStructure((IntPtr)((UInt32)ptArray[0] + j * Marshal.SizeOf(typeof(D300SysUI.SSIDLIST))), typeof(D300SysUI.SSIDLIST));
// mac = "";
// for (int i = 0; i < 6; i++)
// {
// mac += String.Format("{0:X2} ", items[j].MacAddress[i]);
// }
// message += string.Format("AP:{0},MAC:{1},dBm:{2} \r\n", Encoding.GetEncoding("ASCII").GetString(items[j].Ssid, 0, (int)(items[j].SsidLength)), mac, items[j].Rssi);
// }
//}
//Marshal.FreeHGlobal(ptArray[0]);
//MessageBox.Show(message);
If you have defined SSIDLISTNET as a cTypes structure, you just allocate the desired number of these. If the maximum the API will return is 30, allocating that number of instances is a simple and straightforward solution.
SSIDlist = SSIDLISTNET * 30
If you are very constrained on memory, you can probably copy over the required actual number of items to a new list which only holds that many, and del SSIDlist to free up the memory you reserved for this list (or let it go out of scope).

why cv2.bitwise_and function of opencv-python returns four element array on single scalar value

I'm trying to understand cv2.bitwise_and function of opencv-python. So I tried it as:
import cv2
cv2.bitwise_and(1,1)
above code returns
array([[1.],
[0.],
[0.],
[0.]])
I don't understand why it returns this.
Documentation says :
dst(I) = src1(I) ^ src2(I) if mask(I) != 0
according to this output should be single value 1. where am I going wrong?
The documentation says clearly that the function performs the operations dst(I) = src1(I) ^ src2(I) if mask(I) != 0 if the inputs are two arrays of the same size.
So try:
import numpy as np # Opecv works with numpy arrays
import cv2
a = np.uint8([1])
b = np.uint8([1])
cv2.bitwise_and(a, b)
That code returns:
array([[1]], dtype=uint8)
That is a one dimensional array containing the number 1.
The documentation also mentions that the operation can be done with an array and a scalar, but not with two scalars, so the input cv2.bitwise_and(1,1) is not correct.
The documentation is a bit vague in this aspect, and it will take some digging through both source, as well as docs to properly explain what's happening.
First of all -- scalars. In context of data types, we have a cv::Scalar, which is actually a specialization of template cv::Scalar_. It represents a 4-element vector, and derives from cv::Vec -- a template representing a fixed size vector, which is again a special case of cv::Matx, a class representing small fixed size matrices.
That's scalar the data type, however in the context of the bitwise_and (and related functions), the concept what is and isn't a scalar is much looser -- the function in fact is not aware that gave it an instance of cv::Scalar.
If you look at the signature of the function, you'll notice that the inputs are InputArrays. So the inputs are always arrays, but it's possible that some of their properties differ (kind, element type, size, dimensionality, etc.).
The specific check in the code verifies that size, type and kind match. If that's the case (and in your scenario it is), the operation dst(I) = src1(I) ^ src2(I) if mask(I) != 0 runs.
Otherwise it will check whether one of the input arrays represents a scalar. It uses function checkScalar to do that, and the return statement says most of it:
return sz == Size(1, 1)
|| sz == Size(1, cn) || sz == Size(cn, 1)
|| (sz == Size(1, 4) && sc.type() == CV_64F && cn <= 4);
Anything that has size 1 x 1
Anything that size 1 x cn or cn x 1 (where cn is the number of channels if the other input array).
Anything that has size 1 x 4 and elements are 64bit floating point values, but only when the other input array has 4 or fewer channels.
The last case matches both the default cv::Scalar (which, as we have seen earlier, is a cv::Matx<double,4,1>), as well as cv::Mat(4,1,CF_64F).
As an intermission, let's test some of what we learned above.
Code:
cv::Scalar foo(1), bar(1);
cv::Mat result;
cv::bitwise_and(foo, bar, result);
std::cout << result << '\n';
std::cout << "size : " << result.size() << '\n';
std::cout << "type==CV_64FC1 : " << (result.type() == CV_64FC1 ? "yes" : "no") << '\n';
Output:
[1;
0;
0;
0]
size : [1 x 4]
type==CV_64FC1 : yes
Having covered the underlying C++ API, let's look at the Python bindings. The generator that creates the wrappers for Python API is fairly complex, so let's skip that, and instead inspect a relevant snippet of what it generates for bitwise_and:
using namespace cv;
{
PyObject* pyobj_src1 = NULL;
Mat src1;
PyObject* pyobj_src2 = NULL;
Mat src2;
PyObject* pyobj_dst = NULL;
Mat dst;
PyObject* pyobj_mask = NULL;
Mat mask;
const char* keywords[] = { "src1", "src2", "dst", "mask", NULL };
if( PyArg_ParseTupleAndKeywords(args, kw, "OO|OO:bitwise_and", (char**)keywords, &pyobj_src1, &pyobj_src2, &pyobj_dst, &pyobj_mask) &&
pyopencv_to(pyobj_src1, src1, ArgInfo("src1", 0)) &&
pyopencv_to(pyobj_src2, src2, ArgInfo("src2", 0)) &&
pyopencv_to(pyobj_dst, dst, ArgInfo("dst", 1)) &&
pyopencv_to(pyobj_mask, mask, ArgInfo("mask", 0)) )
{
ERRWRAP2(cv::bitwise_and(src1, src2, dst, mask));
return pyopencv_from(dst);
}
}
PyErr_Clear();
We can see that parameters that correspond to InputArray or OutputArray are loaded into a cv::Mat instance. Let's look at the part of pyopencv_to that corresponds to your scenario:
if( PyInt_Check(o) )
{
double v[] = {static_cast<double>(PyInt_AsLong((PyObject*)o)), 0., 0., 0.};
m = Mat(4, 1, CV_64F, v).clone();
return true;
}
A cv::Mat(4, 1, CV_64F) (recall from earlier that this fits the test for scalar) containing the input integer cast to double, with the remaining 3 position padded with zeros.
Since no destination is provided, a Mat will be allocated automatically, of the same size and type as inputs. On return to Python, the Mat will become a numpy array.

Python to C for loop conversion

I have the following python code:
r = range(1,10)
r_squared = []
for item in r:
print item
r_squared.append(item*item)
How would I convert this code to C? Is there something like a mutable array in C or how would I do the equivalent of the python append?
simple array in c.Arrays in the C are Homogenous
int arr[10];
int i = 0;
for(i=0;i<sizeof(arr);i++)
{
arr[i] = i; // Initializing each element seperately
}
Try using vectors in C go through this link
/ vector-usage.c
#include <stdio.h>
#include "vector.h"
int main() {
// declare and initialize a new vector
Vector vector;
vector_init(&vector);
// fill it up with 150 arbitrary values
// this should expand capacity up to 200
int i;
for (i = 200; i > -50; i--) {
vector_append(&vector, i);
}
// set a value at an arbitrary index
// this will expand and zero-fill the vector to fit
vector_set(&vector, 4452, 21312984);
// print out an arbitrary value in the vector
printf("Heres the value at 27: %d\n", vector_get(&vector, 27));
// we're all done playing with our vector,
// so free its underlying data array
vector_free(&vector);
}
Arrays in C are mutable by default, in that you can write a[i] = 3, just like Python lists.
However, they're fixed-length, unlike Python lists.
For your problem, that should actually be fine. You know the final size you want; just create an array of that size, and assign to the members.
But of course there are problems for which you do need append.
Writing a simple library for appendable arrays (just like Python lists) is a pretty good learning project for C. You can also find plenty of ready-made implementations if that's what you want, but not in the standard library.
The key is to not use a stack array, but rather memory allocated on the heap with malloc. Keep track of the pointer to that memory, the capacity, and the used size. When the used size reaches the capacity, multiply it by some number (play with different numbers to get an idea of how they affect performance), then realloc. That's just about all there is to it. (And if you look at the CPython source for the list type, that's basically the same thing it's doing.)
Here's an example. You'll want to add some error handling (malloc and realloc can return NULL) and of course the rest of the API beyond append (especially a delete function, which will call free on the allocated memory), but this should be enough to show you the idea:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int *i;
size_t len;
size_t capacity;
} IntArray;
IntArray int_array_make() {
IntArray a = {
.i = malloc(10 * sizeof(int)),
.len = 0,
.capacity = 10
};
return a;
}
void int_array_append(IntArray *a, int value) {
if (a->len+1 == a->capacity) {
size_t new_capacity = (int)(a->capacity * 1.6);
a->i = realloc(a->i, new_capacity * sizeof(int));
a->capacity = new_capacity;
}
a->i[a->len++] = value;
}
int main(int argc, char *argv[]) {
IntArray a = int_array_make();
for (int i = 0; i != 50; i++)
int_array_append(&a, i);
for (int i = 0; i != a.len; ++i)
printf("%d ", a.i[i]);
printf("\n");
}
c doesnt have any way of dynamically increasing the size of the array like in python. arrays here are of fixed length
if you know the size of the array that you will be using, u can use this kind of declaration, like this
int arr[10];
or if you would want to add memery on the fly (in runtime), use malloc call along with structure (linked lists)

Categories

Resources