Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shakeb #11

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions liboptv/include/parameters.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,33 @@ typedef struct {
mm_np *mm;
} control_par;

typedef struct {
int seq_first;
int seq_last;
int max_shaking_points;
int max_shaking_frames;
} shaking_par;

/* compare_shaking_par(shaking_par *, shaking_par * ) checks deep equality between two shaking_par structs.
Arguments: shaking_par * s1, shaking_par * s2 - pointers to the structs for comparison.

Returns:
True (1) if equal, false (0) otherwise.
*/
int compare_shaking_par(shaking_par * s1, shaking_par * s2);

/* read_shaking_par() reads 4 shaking parameters from a text file line by line
Arguments:
char *filename - path to the text file containing the parameters.
Returns:
Pointer to a newly-allocated shaking_par structure. Don't forget to free
the new memory that is allocated for the image names.
Returns NULL in case of any reading error.
*/
shaking_par * read_shaking_par(char* filename);

control_par * read_control_par(char *filename);

void free_control_par(control_par *cp);

/* Checks deep equality between two mm_np struct instances.
Expand Down
54 changes: 54 additions & 0 deletions liboptv/src/parameters.c
Original file line number Diff line number Diff line change
Expand Up @@ -337,3 +337,57 @@ int compare_mm_np(mm_np *mm_np1, mm_np *mm_np2)
return 0;
return 1;
}

/* read_shaking_par() reads 4 shaking parameters from a text file line by line

Arguments:
char *filename - path to the text file containing the parameters.

Returns:
Pointer to a newly-allocated shaking_par structure. Don't forget to free
the new memory that is allocated for the image names.
Returns NULL in case of any reading error.
*/
shaking_par * read_shaking_par(char* filename) {
FILE *par_file;
shaking_par *ret; //returned pointer to shaking_par struct

par_file = fopen(filename, "r");
if (par_file == NULL) {
printf("Failed to open %s\n", filename);
return NULL;
}

ret = (shaking_par *) malloc(sizeof(shaking_par));

if ( fscanf(par_file, "%d\n", &(ret->seq_first)) == 0
|| fscanf(par_file, "%d\n", &(ret->seq_last)) == 0
|| fscanf(par_file, "%d\n", &(ret->max_shaking_points)) == 0
|| fscanf(par_file, "%d\n", &(ret->max_shaking_frames)) == 0 )
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're going through the trouble of all the 'or's then we don't need a goto.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My logic is: If one of 'fcanf's returns 0 then the parameter was not read and it is considered an error.
What do I miss here?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of course. My problem is not twith the or, it's with the goto. The goto is there to avoid nesting, but with the short-circuit 'or' you don't nest so much, so you can do a simple if/else.

goto handle_error;

fclose(par_file);
return ret;

handle_error:
printf("Error reading shaking parameters from %s\n", filename);
free(ret);
fclose(par_file);
return NULL;
}

/* compare_shaking_par(shaking_par *, shaking_par * ) checks deep equality between two shaking_par structs.
Arguments: shaking_par * s1, shaking_par * s2 - pointers to the structs for comparison.

Returns:
True (1) if equal, false (0) otherwise.
*/
int compare_shaking_par(shaking_par * s1, shaking_par * s2) {
if ( s1->seq_first != s2->seq_first
|| s1->seq_last != s2->seq_last
|| s1->max_shaking_points != s2->max_shaking_points
|| s1->max_shaking_frames != s2->max_shaking_frames )
return 0;
return 1;
}

21 changes: 20 additions & 1 deletion liboptv/tests/check_parameters.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,20 @@
#include <stdio.h>
#include "parameters.h"

START_TEST( test_read_shaking_par)
{
shaking_par * sp_test; //TODO change back to 100!
shaking_par sp_correct = { 410000, 411055, 100, 3 };//according to current contents in shaking.par text file

sp_test = read_shaking_par("testing_fodder/parameters/shaking.par");

fail_unless(compare_shaking_par(sp_test, &sp_correct));

sp_correct.seq_first=0;
fail_if(compare_shaking_par(sp_test, &sp_correct));
}
END_TEST

START_TEST(test_read_compare_mm_np_par)
{
mm_np mm1,mm2;
Expand Down Expand Up @@ -128,8 +142,13 @@ END_TEST

Suite* fb_suite(void) {
Suite *s = suite_create ("Parameters handling");
TCase *tc;

tc=tcase_create ("Read shaking parameters");
tcase_add_test(tc, test_read_shaking_par);
suite_add_tcase (s, tc);

TCase *tc = tcase_create ("Read sequence parameters");
tc = tcase_create ("Read sequence parameters");
tcase_add_test(tc, test_read_sequence_par);
suite_add_tcase (s, tc);

Expand Down
9 changes: 9 additions & 0 deletions py_bind/optv/parameters.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,16 @@ cdef extern from "optv/parameters.h":
double d[3]
double n3
int lut

ctypedef struct shaking_par:
int seq_first
int seq_last
int max_shaking_points
int max_shaking_frames

cdef class MultimediaParams:
cdef mm_np* _mm_np

cdef class ShakingParams:
cdef shaking_par* _shaking_par

103 changes: 82 additions & 21 deletions py_bind/optv/parameters.pyx
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
#Implementation of Python binding to parameters.h
# Implementation of Python binding to parameters.h
from libc.stdlib cimport malloc, free
import numpy

cdef extern from "optv/parameters.h":
shaking_par * c_read_shaking_par "read_shaking_par"(char * file_name)
int c_compare_shaking_par "compare_shaking_par"(shaking_par * s1, shaking_par * s2)

cdef class MultimediaParams:

def __init__(self, **kwargs):
def __init__(self, nlay, n1, n2, d, n3, lut):

self._mm_np = <mm_np *>malloc(sizeof(mm_np))
self._mm_np = < mm_np *> malloc(sizeof(mm_np))

self.set_nlay(kwargs['nlay'])
self.set_n1(kwargs['n1'])
self.set_n2(kwargs['n2'])
self.set_d(kwargs['d'])
self.set_n3(kwargs['n3'])
self.set_lut(kwargs['lut'])
self.set_nlay(nlay)
self.set_n1(n1)
self.set_n2(n2)
self.set_d(d)
self.set_n3(n3)
self.set_lut(lut)

def get_nlay(self):
return self._mm_np[0].nlay
Expand All @@ -27,7 +31,7 @@ cdef class MultimediaParams:
def set_n1(self, n1):
self._mm_np[0].n1 = n1

def get_n2(self):#TODO return numpy
def get_n2(self):
arr_size = sizeof(self._mm_np[0].n2) / sizeof(self._mm_np[0].n2[0])
n2_np_arr = numpy.empty(arr_size)
for i in range(len(n2_np_arr)):
Expand Down Expand Up @@ -63,16 +67,16 @@ cdef class MultimediaParams:
self._mm_np[0].lut = lut

def __str__(self):
n2_str="{"
for i in range(sizeof(self._mm_np[0].n2) / sizeof(self._mm_np[0].n2[0]) -1 ):
n2_str = n2_str+ str(self._mm_np[0].n2[i]) + ", "
n2_str += str(self._mm_np[0].n2[i+1]) + "}"
n2_str = "{"
for i in range(sizeof(self._mm_np[0].n2) / sizeof(self._mm_np[0].n2[0]) - 1):
n2_str = n2_str + str(self._mm_np[0].n2[i]) + ", "
n2_str += str(self._mm_np[0].n2[i + 1]) + "}"

d_str="{"
for i in range(sizeof(self._mm_np[0].d) / sizeof(self._mm_np[0].d[0]) -1 ) :
d_str = "{"
for i in range(sizeof(self._mm_np[0].d) / sizeof(self._mm_np[0].d[0]) - 1) :
d_str += str(self._mm_np[0].d[i]) + ", "

d_str += str(self._mm_np[0].d[i+1]) + "}"
d_str += str(self._mm_np[0].d[i + 1]) + "}"

return "nlay=\t{} \nn1=\t{} \nn2=\t{} \nd=\t{} \nn3=\t{} \nlut=\t{} ".format(
str(self._mm_np[0].nlay),
Expand All @@ -82,6 +86,63 @@ cdef class MultimediaParams:
str(self._mm_np[0].n3),
str(self._mm_np[0].lut))

def __dealloc__(self):
free(self._mm_np)

def __dealloc__(self):
free(self._mm_np)

# Wrapping the shaking_par C struct for pythonic access
# Binding the read_shaking_par C function
# Objects of this type can be checked for equality using "==" and "!=" operators
cdef class ShakingParams:

def __init__(self, seq_first, seq_last, max_shaking_points, max_shaking_frames):
self._shaking_par = < shaking_par *> malloc(sizeof(shaking_par))
self.set_seq_first(seq_first)
self.set_seq_last(seq_last)
self.set_max_shaking_points(max_shaking_points)
self.set_max_shaking_frames(max_shaking_frames)

# Reads shaking parameters from specified full file path
def read_shaking_par(self, file_name):
self._shaking_par = c_read_shaking_par(file_name)

# Checks for equality between this and other ShakingParams objects
# Gives the ability to use "==" and "!=" operators on two ShakingParams objects
def __richcmp__(ShakingParams self, ShakingParams other, operator):
if (operator==2): # "==" action was performed
if (c_compare_shaking_par(self._shaking_par,
other._shaking_par) != 0):
return True
else:
return False
else:
if(operator==3): # "!=" action was performed
return not self==other # change the operator to "==" and recursively check the opposite

# Getters and setters
def get_seq_first(self):
return self._shaking_par[0].seq_first

def set_seq_first(self, seq_first):
self._shaking_par[0].seq_first = seq_first

def get_seq_last(self):
return self._shaking_par[0].seq_last

def set_seq_last(self, seq_last):
self._shaking_par[0].seq_last = seq_last

def get_max_shaking_points(self):
return self._shaking_par[0].max_shaking_points

def set_max_shaking_points(self, max_shaking_points):
self._shaking_par[0].max_shaking_points = max_shaking_points

def get_max_shaking_frames(self):
return self._shaking_par[0].max_shaking_frames

def set_max_shaking_frames(self, max_shaking_frames):
self._shaking_par[0].max_shaking_frames = max_shaking_frames

# Memory freeing
def __dealloc__(self):
free(self._shaking_par)
25 changes: 0 additions & 25 deletions py_bind/test/test_MultimediaParams.py

This file was deleted.

65 changes: 65 additions & 0 deletions py_bind/test/test_parameters_bindings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import unittest
from optv.parameters import MultimediaParams, ShakingParams
import numpy

class Test_Parameters_binding(unittest.TestCase):
def test_mm_np_instantiation(self):

n2_np = numpy.array([11,22,33])
d_np = numpy.array([55,66,77])

m = MultimediaParams(nlay=3, n1=2, n2=n2_np, d=d_np, n3=4, lut=1)

self.failUnlessEqual(m.get_nlay(), 3)
self.failUnlessEqual(m.get_n1(), 2)
self.failUnlessEqual(m.get_n3(), 4)
self.failUnlessEqual(m.get_lut(), 1)

numpy.testing.assert_array_equal(m.get_d(), d_np)
numpy.testing.assert_array_equal(m.get_n2(), n2_np)

self.failUnlessEqual(m.__str__(), "nlay=\t3 \nn1=\t2.0 \nn2=\t{11.0, 22.0, 33.0}"
+ " \nd=\t{55.0, 66.0, 77.0} \nn3=\t4.0 \nlut=\t1 ")

def test_shaking_par_instantiation(self):

# manually assign values to ShakingParams object and check the assignments were made correctly
sp1 = ShakingParams(222, 333, 444, 555)

self.failUnlessEqual(sp1.get_seq_first(), 222)
self.failUnlessEqual(sp1.get_seq_last(), 333)
self.failUnlessEqual(sp1.get_max_shaking_points(), 444)
self.failUnlessEqual(sp1.get_max_shaking_frames(), 555)

# checking C read_shaking_par function
# read shaking parameters from a file and
# verify the parameters were read correctly according to contents of specified file
sp1.read_shaking_par("/home/student/Desktop/Max_OpenPtv/" +
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardcoded path makes the test fail for anyone but you. We said you'll make a special tests/testing_fodder/ directory for the Python stuff.
(The test passes when manually changing the path to point to the correct file).

"liboptv/tests/testing_fodder/parameters/shaking.par")
self.failUnlessEqual(sp1.get_seq_first(), 410000)
self.failUnlessEqual(sp1.get_seq_last(), 411055)
self.failUnlessEqual(sp1.get_max_shaking_points(), 100)
self.failUnlessEqual(sp1.get_max_shaking_frames(), 3)

# manually assigning values exactly like in the shaking parameters testing file
# to another ShakingParams object
sp2 = ShakingParams(410000, 411055, 100, 3)

self.failUnlessEqual(sp2.get_seq_first(), 410000)
self.failUnlessEqual(sp2.get_seq_last(), 411055)
self.failUnlessEqual(sp2.get_max_shaking_points(), 100)
self.failUnlessEqual(sp2.get_max_shaking_frames(), 3)

# now we have two identical ShakingParams objects (sp1 and sp2) for comparison
self.assertTrue(sp1==sp2)
self.assertFalse(sp1!=sp2)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the difference between this line and the one before? Same for the following occurrence on lines 59-60.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comparison is performed through function defined in ShakingParams:

 def __richcmp__ (ShakingParams self, ShakingParams other, operator):  

The third parameter is integer value to indicate the operation performed: 2 for '=' , 3 for '!=' (you must refer to them separately).
For more info: http://docs.cython.org/src/userguide/special_methods.html#rich-comparisons

So in order to check the comparisons I must pass '==' as well as '!=' .

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. This is not trivial, better add a comment explaining it.


#change one attribute in sp2 and assert the results of equality comparison are now inverted
sp2.set_max_shaking_frames(-999)
self.assertFalse(sp1==sp2)
self.assertTrue(sp1!=sp2)


if __name__ == "__main__":
#import sys;sys.argv = ['', 'Test.testName']
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove commented-out code.

unittest.main()