Matlab to OpenCV conversion - optimization? - c++

I am converting Matlab code to OpenCV "C/cpp" code. And I have some doubts as below.
A = [ 2; 10; 7; 1; 3; 6; 10; 10; 2; 10];
ind = [10; 5; 9; 2];
B is a submatrix of A ; Elements of matrix B are elements of A at locations specified in ind.
B = [10 3; 2; 10];
In Matlab, I just use
B = A(ind);
In C using OpenCV,
for ( int i = 0; i < ind.rows; i++) {
B.at<int>(i,0) = A.at<int>(ind.at<int>(i,0), 0);
}
Is there a way to do it without using for loop?

If you are looking for an tidy way of copying. I would suggest you define a function
Here is a STL-like implementation of copy at given position
#include<vector>
#include<cstdio>
using namespace std;
/**
* Copies the elements all elements of B to A at given positions.
* indexing array ranges [ind_first, ind_lat)
* e.g
* int A[]= {0, 2, 10, 7, 1, 3, 6, 10, 10, 2, 10};
* int B[] = {-1, -1, -1, -1};
* int ind[] = {10, 5, 9, 2};
* copyat(B, A, &ind[0], &ind[3]);
* // results: A:[0,2,10,7,1,-1,6,10,10,-1,-1]
*/
template<class InputIterator, class OutputIterator, class IndexIterator>
OutputIterator copyat (InputIterator src_first,
OutputIterator dest_first,
IndexIterator ind_first,
IndexIterator ind_last)
{
while(ind_first!=ind_last) {
*(dest_first + *ind_first) = *(src_first);
++ind_first;
}
return (dest_first+*ind_first);
}
int main()
{
int A[]= {0, 2, 10, 7, 1, 3, 6, 10, 10, 2, 10};
int B[] = {-1, -1, -1, -1};
int ind[] = {10, 5, 9, 2};
copyat(B, A, &ind[0], &ind[3]);
printf("A:[");
for(int i=0; i<10; i++)
printf("%d,", A[i]);
printf("%d]\n",A[10]);
}

Related

Algorithms - Circular Array Rotation

Is this linear complexity implementation of circular array rotation correct?
n = number of elements
k = number of rotations
int write_to = 0;
int copy_current = 0;
int copy_final = a[0];
int rotation = k;
int position = 0;
for (int i = 0; i < n; i++) {
write_to = (position + rotation) % n;
copy_current = a[write_to];
a[write_to] = copy_final;
position = write_to;
copy_final = copy_current;
}
No.
Consider this example.
#include <iostream>
int main(void) {
int n = 6;
int k = 2;
int a[] = {1, 2, 3, 4, 5, 6};
int write_to = 0;
int copy_current = 0;
int copy_final = a[0];
int rotation = k;
int position = 0;
for (int i = 0; i < n; i++) {
write_to = (position + rotation) % n;
copy_current = a[write_to];
a[write_to] = copy_final;
position = write_to;
copy_final = copy_current;
}
for (int i = 0; i < n; i++) {
std::cout << a[i] << (i + 1 < n ? ' ' : '\n');
}
return 0;
}
Expected result:
5 6 1 2 3 4
Actual result:
3 2 1 4 1 6
Using stl::rotate on std::array, you can left rotate by, say 2, as:
std::array<int, 6> a{1, 2, 3, 4, 5, 6};
std::rotate(begin(a), begin(a) + 2, end(a)); // left rotate by 2
to yield: 3 4 5 6 1 2, or right-rotate by, say 2, as:
std::rotate(begin(a), end(a) - 2, end(a)); // right rotate by 2
to yield: 5 6 1 2 3 4, with linear complexity.
Rotate an Array of length n for k times in left or right directions.
The code is in Java
I define a Direction Enum:
public enum Direction {
L, R
};
Rotation with times and direction:
public static final void rotate(int[] arr, int times, Direction direction) {
if (arr == null || times < 0) {
throw new IllegalArgumentException("The array must be non-null and the order must be non-negative");
}
int offset = arr.length - times % arr.length;
if (offset > 0) {
int[] copy = arr.clone();
for (int i = 0; i < arr.length; ++i) {
int j = (i + offset) % arr.length;
if (Direction.R.equals(direction)) {
arr[i] = copy[j];
} else {
arr[j] = copy[i];
}
}
}
}
Complexity: O(n).
Example:
Input: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Rotate 3 times left
Output: [4, 5, 6, 7, 8, 9, 10, 1, 2, 3]
Input: [4, 5, 6, 7, 8, 9, 10, 1, 2, 3]
Rotate 3 times right
Output: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

function using unordered_map to determine subarray indices failing

I'm attempting to cout the elements of input array "arr" that was used to determine max sum of a subarray, hereinafter named "maxSum" (which is determined elsewhere, and confirmed to be correct). The function showSubArray() accepts as parameters the array arr, the length of the array n, and maxSum. Input array is positive and negative ints. Below is a set of test arrays with the result. Fail means that arr[0] is printed to the screen with a space separating them INFINITELY. I can't see any discernable pattern in the input that would cause this. Any help greatly appreciated and I am not beholden to the unordered_map approach. Getting the indices from the function that determined the maxSum is not an acceptable solution.
#include <unordered_map>
#include <iostream>
using std::cout;
int main() {
//int arr[] = { 1, 4, -9, 8, 1, 3, 3, 1, -1, -4, -6, 2, 8, 19, -10, -11 };
// runs ok, inputs: n=16, maxSum = 34
//int arr[] = { 2, 9, 8, 6, 5, -11, 9, -11, 7, 5, -1, -8, -3, 7, -2 };
// ***fails, inputs: n=15, maxSum = 30
//int arr[] = { 10, -11, -1, -9, 33, -45, 23, 24, -1, -7, -8, 19 };
// runs ok, n=12, maxSum = 50
//int arr[] = { 31, -41, 59, 26, -53, 58, 97, -93, -23, 84 };
// runs ok n=10 maxSum = 187
//int arr[] = { 3, 2, 1, 1, -8, 1, 1, 2, 3 };
// ***fails, inputs: n=9 maxSum = 7
int arr[] = { 12, 99, 99, -99, -27, 0, 0, 0, -3, 10 };
// ***fails, n=10 maxSum = 210
//int arr[] = { -2, 1, -3, 4, -1, 2, 1, -5, 4 };
// runs ok, inputs: n=9 maxSum = 6
showSubArray(arr, n, maxSum);
return 0;
}
void showSubArray(int arr[], int n, int maxSum) {
std::unordered_map<int, int> aMap;
int accumulator = 0;
for (int i = 0; i < n; i++) {
accumulator += arr[i];
if (accumulator == maxSum) {
for(int j = 0; j <= i; j++) {
// ACB found error here ^ (I had it as "i")
cout << arr[j];
cout << " ";
}
cout << '\n';
return;
}
if (aMap.find(accumulator - maxSum) != aMap.end()) {
for (int j = aMap[accumulator - maxSum] + 1; j <= i; j++) {
cout << arr[j];
cout << " ";
}
cout << '\n';
return;
}
aMap[accumulator] = i;
}
cout << "Subarray not found!\n";
}
if (accumulator == maxSum) {
for(int j = 0; j <= i; i++) {
you are incrementing i here but you want to increment j cause 0 will always be smaller i for i > 0 until it overflows

Optimizing the number of calls to expensive function

I have an mainFun that takes four parameters x, a, b, and c, all vector-valued and possibly of varying length. This function calls expensiveFun that is computationally expensive so I'd like to reduce the number of calls to expensiveFun. This function needs to be called for each value in x[i], a[i], b[i], c[i] and if a, b, or c are of shorter length, then they need to be "wrapped" (their index is in modulo a[i % a.size()]). It would be the best to precompute the expensiveFun for each possible distinct value of x (i.e. all integers 0,...,max(x)) and then just fill-in the output out by out[i] = precomputedValues[x[i]]. This can be easily achieved if a, b, and c have the same length (example below), but it gets ugly if they are not. Is there any way to make it more efficient for case when the lengths of parameter vectors differ?
Below I provide a reproducible example. It's a simplified code, written just to serve as example.
std::vector<int> expensiveFun(int x, int a, int b, int c) {
std::vector<int> out(x+1);
out[0] = a+b*c;
for (int i = 1; i <= x; i++)
out[i] = out[i-1] * i + a * (b+c);
return out;
}
std::vector<int> mainFun(
std::vector<int> x,
std::vector<int> a,
std::vector<int> b,
std::vector<int> c
) {
int n = x.size();
int a_size = a.size();
int b_size = b.size();
int c_size = c.size();
std::vector<int> out(n);
// easy
if (a_size == b_size && b_size == a_size) {
int max_x = 0;
for (int j = 0; j < n; j++)
if (x[j] > max_x)
max_x = x[j];
for (int i = 0; i < a_size; i++) {
int max_x = 0;
for (int j = 0; j < n; j += a_size) {
if (x[j] > max_x)
max_x = x[j];
}
std::vector<int> precomputedValues = expensiveFun(max_x, a[i], b[i], c[i]);
for (int j = i; j < n; j += a_size) {
out[j] = precomputedValues[x[j]];
}
}
// otherwise give up
} else {
for (int j = 0; j < n; j++) {
out[j] = expensiveFun(x[j], a[j % a_size], c[j % c_size], c[j % c_size]).back();
}
}
return out;
}
Example input:
x = {0, 1, 5, 3, 2, 1, 0, 4, 4, 2, 3, 4, 1}
a = {1, 2, 3}
b = {1, 2}
c = {3, 4, 5, 6}
Parameters should be folded so that they become:
x = {0, 1, 5, 3, 2, 1, 0, 4, 4, 2, 3, 4, 1}
a = {1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1}
b = {1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1}
c = {3, 4, 5, 6, 3, 4, 5, 6, 3, 4, 5, 6, 3}
The output is not important at the moment since the main issue in here is about efficiently dealing with varying-size parameter vectors.
Memoize your function.
Once you compute a vector for a combination of a, b, and c, store it in an std::unordered_map. The next time you see the same combination, you retrieve the vector that you have already computed - the classic approach of paying with computer memory for computation speed-up.
std::map<std::tuple<int,int,int>,std::vector<int>> memo;
int expensiveFunMemo(int x, int xMax, int a, int b, int c) {
assert(x <= xMax);
std::vector<int>& out = memo[std::make_tuple(a, b, c)];
if (!out.size()) {
out.push_back(a+b*c);
for (int i = 1; i <= xMax; i++)
out.push_back(out[i-1] * i + a * (b+c));
}
assert(out.size == xMax+1);
return out[x];
}
This way you would never compute expensiveFunMemo for any combination of {a, b, c} more than once.
Your mainFun becomes simpler, too:
std::vector<int> mainFun(
const std::vector<int>& x,
const std::vector<int>& a,
const std::vector<int>& b,
const std::vector<int>& c
) {
size_t n = x.size();
size_t a_size = a.size();
size_t b_size = b.size();
size_t c_size = c.size();
std::vector<int> out(n);
int xMax = *std::max_element(x.begin(), x.end());
for (size_t j = 0 ; j < n ; j++) {
out[j] = expensiveFunMemo(x[j], xMax, a[j % a_size], c[j % c_size], c[j % c_size]);
}
return out;
}
Note: this solution uses std::map<K,V> instead of std::unordered_map<K,V> because std::tuple<...> lacks a generic hash function. This Q&A offers a solution to fix this problem.

Pixel-wise median of sequence of cv::Mat's

Note: I am NOT asking about Median Filter.
I have a sequence of images let us say:
std::array<cv::Mat,N> sequence;
I want to blend all those images in one. This one image should satisfies:
Each pixel of the new image is the median of its corresponding pixels from the sequence. In other words:
Result(i,j)=median(sequence[0](i,j), sequence[1](i,j), ..., sequence[N](i,j));
Is there built-in function for doing that? What would be the fastest way?
What I tried till now: To iterate over each pixel from all the sequence and sort then take the median then store it in the result. However, it is so overkill.
You can compute the sequential median for each position using histograms.
Assuming that you're using Mat1b images, each histogram would have 256 values.
You need to store the histogram, as well as the sum of all bins:
struct Hist {
vector<short> h;
int count;
Hist() : h(256, 0), count(0) {};
};
The median value is the index in the histogram that corresponds to half of the pixels count / 2. Snippet from Rosetta Code:
int i;
int n = hist.count / 2; // 'hist' is the Hist struct at a given pixel location
for (i = 0; i < 256 && ((n -= hist.h[i]) >= 0); ++i);
// 'i' is the median value
When you add or remove an image, you update the histogram for each pixel location, and recompute the median value. This operation is quite fast because you don't need to sort.
There are some drawback to this:
This will work only for uchar values, otherwise the length of each histogram will be too large
This approach will use a lot of RAM since it needs rows x cols histograms. It may not work for large images.
The following implementation works for single channel images, but it can be easily extended to 3 channels.
You can use an approach based on two heaps, or approximate methods. You can find details here:
Find running median from a stream of integers
Rolling median algorithm in C
Find median value from a growing set
Code:
#include <vector>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
struct Hist {
vector<short> h;
int count;
Hist() : h(256, 0), count(0) {};
};
void addImage(vector<Mat1b>& images, Mat1b& img, vector<vector<Hist>>& M, Mat1b& med)
{
assert(img.rows == med.rows);
assert(img.cols == med.cols);
for (int r = 0; r < img.rows; ++r) {
for (int c = 0; c < img.cols; ++c){
// Add pixel to histogram
Hist& hist = M[r][c];
++hist.h[img(r, c)];
++hist.count;
// Compute median
int i;
int n = hist.count / 2;
for (i = 0; i < 256 && ((n -= hist.h[i]) >= 0); ++i);
// 'i' is the median value
med(r,c) = uchar(i);
}
}
// Add image to my list
images.push_back(img.clone());
}
void remImage(vector<Mat1b>& images, int idx, vector<vector<Hist>>& M, Mat1b& med)
{
assert(idx >= 0 && idx < images.size());
Mat1b& img = images[idx];
for (int r = 0; r < img.rows; ++r) {
for (int c = 0; c < img.cols; ++c){
// Remove pixel from histogram
Hist& hist = M[r][c];
--hist.h[img(r, c)];
--hist.count;
// Compute median
int i;
int n = hist.count / 2;
for (i = 0; i < 256 && ((n -= hist.h[i]) >= 0); ++i);
// 'i' is the median value
med(r, c) = uchar(i);
}
}
// Remove image from list
images.erase(images.begin() + idx);
}
void init(vector<vector<Hist>>& M, Mat1b& med, int rows, int cols)
{
med = Mat1b(rows, cols, uchar(0));
M.resize(rows);
for (int i = 0; i < rows; ++i) {
M[i].resize(cols);
}
}
int main()
{
// Your images... be sure that they have the same size
Mat1b img0 = imread("path_to_image", IMREAD_GRAYSCALE);
Mat1b img1 = imread("path_to_image", IMREAD_GRAYSCALE);
Mat1b img2 = imread("path_to_image", IMREAD_GRAYSCALE);
resize(img0, img0, Size(800, 600));
resize(img1, img1, Size(800, 600));
resize(img2, img2, Size(800, 600));
int rows = img0.rows;
int cols = img0.cols;
vector<Mat1b> images; // All your images, needed only if you need to remove an image
vector<vector<Hist>> M; // histograms
Mat1b med; // median image
// Init data strutctures
init(M, med, rows, cols);
// Add images. 'med' will be the median image and will be updated each time
addImage(images, img0, M, med);
addImage(images, img1, M, med);
addImage(images, img2, M, med);
// You can also remove an image from the median computation
remImage(images, 2, M, med);
// Hey, same median as img0 and img1 ;D
return 0;
}
You can use the following technique if the number of images in your sequence is odd.
Prepare an N (which is odd) channel image from the sequence of images that you have
Reshape this image into a 1-channel column vector
Now apply a median filter of size N to this column vector. As the image is a 1-channel column vector, the filter will calculate the median of the channels(of course, there will be some additional calculations that are not useful to us)
Reshape this filtered image into its original form having N channels and the original number of rows and columns
Pick the middle channel of this N-channel image, which contains the median image of the sequence
Below I've illustrated the above items with a simple code and its output.
individual channels
channel 0:
[1, 1, 1;
1, 1, 1;
1, 1, 1]
channel 1:
[2, 2, 2;
2, 2, 2;
2, 2, 2]
channel 2:
[3, 3, 3;
3, 3, 3;
3, 3, 3]
channel 3:
[4, 4, 4;
4, 4, 4;
4, 4, 4]
channel 4:
[5, 5, 5;
5, 5, 5;
5, 5, 5]
output for N = 3
3-channel image data:
[1, 2, 3, 1, 2, 3, 1, 2, 3;
1, 2, 3, 1, 2, 3, 1, 2, 3;
1, 2, 3, 1, 2, 3, 1, 2, 3]
1-channel column vector image data:
[1; 2; 3; 1; 2; 3; 1; 2; 3; 1; 2; 3; 1; 2; 3; 1; 2; 3; 1; 2; 3; 1; 2; 3; 1; 2; 3]
median of the 1-channel column vector image data:
[1; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 3]
reshaped filtered image data:
[1, 2, 2, 2, 2, 2, 2, 2, 2;
2, 2, 2, 2, 2, 2, 2, 2, 2;
2, 2, 2, 2, 2, 2, 2, 2, 3]
median image data:
[2, 2, 2;
2, 2, 2;
2, 2, 2]
output for N = 5
5-channel image data:
[1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5;
1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5;
1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5]
1-channel column vector image data:
[1; 2; 3; 4; 5; 1; 2; 3; 4; 5; 1; 2; 3; 4; 5; 1; 2; 3; 4; 5; 1; 2; 3; 4; 5; 1; 2
; 3; 4; 5; 1; 2; 3; 4; 5; 1; 2; 3; 4; 5; 1; 2; 3; 4; 5]
median of the 1-channel column vector image data:
[1; 2; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3
; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 4; 5]
reshaped filtered image data:
[1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3;
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3;
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 5]
median image data:
[3, 3, 3;
3, 3, 3;
3, 3, 3]
Code:
// number of channels (= number of images in the sequence)
// N MUST BE ODD
const int N = 5;
// channel data
uchar ch0[] = {1, 1, 1, 1, 1, 1, 1, 1, 1};
uchar ch1[] = {2, 2, 2, 2, 2, 2, 2, 2, 2};
uchar ch2[] = {3, 3, 3, 3, 3, 3, 3, 3, 3};
uchar ch3[] = {4, 4, 4, 4, 4, 4, 4, 4, 4};
uchar ch4[] = {5, 5, 5, 5, 5, 5, 5, 5, 5};
// images
Mat m0 = Mat(3, 3, CV_8U, ch0);
Mat m1 = Mat(3, 3, CV_8U, ch1);
Mat m2 = Mat(3, 3, CV_8U, ch2);
Mat m3 = Mat(3, 3, CV_8U, ch3);
Mat m4 = Mat(3, 3, CV_8U, ch4);
// prepare image sequence
Mat channels[] = {m0, m1, m2, m3, m4};
// put the images into channels of matrix m
Mat m;
merge(channels, N, m);
// reshape data so that we have a single channel column vector as the image
Mat n = m.reshape(1, m.rows * m.cols * m.channels());
// apply median filter to the 1-channel column vector image. filter size must be the number of channels
Mat med;
medianBlur(n, med, N);
cout << N << "-channel image data:" << endl;
cout << m << endl;
cout << "1-channel column vector image data:" << endl;
cout << n << endl;
cout << "median of the 1-channel column vector image data:" << endl;
cout << med << endl;
// reshape the filtered 1-channel column vector image into its original form having N channels
med = med.reshape(N, m.rows);
cout << "reshaped filtered image data:" << endl;
cout << med << endl;
// split the image
split(med, channels);
// extract the middle channel which contains the median image of the sequence
cout << "median image data:" << endl;
cout << channels[(N+1)/2 - 1] << endl;

How to track expanding circle radius

I'm working on a numerical simulation program, for simplicity I recreated the code into expanding circles on a domain bounded on each side. I want to track each circle's radius. If I have this code:
int const N = 10;
int D[N+2][N+2]; //domain bounded on each side
int const nCircle = 4;
int center[nCircle][2] = {{1, 1}, {N, N}, {N, 1}, {1, N}};
void eval(); //function to expand circles
int main() {
for (int n=0;n<5;n++) {
eval();
for (int y=1;y<=N;y++) {
for (int x=1;x<=N;x++) {
printf("%d ", D[x][y]);
}
printf("\n");
}
printf("\n");
}
}
for visualization and simplicity purpose,
add these into global definition
double radius[nCircle] = {2, 2, 2, 2}; //actually unknown, i want to track this
void eval() {
double a;
for (int z=0;z<nCircle;z++) {
for (int y=1;y<=N;y++) {
for (int x=1;x<=N;x++) {
a = pow(x-center[z][0], 2) + pow(y-center[z][1], 2);
if (a <= pow(radius[z], 2))
D[x][y] = 1;
}
}
radius[z] += ((double) rand() / (RAND_MAX));
}
}
How do I do that?
edit:
note that circles might overlap each other, array D only store the union of circle area without information of the intersections.
Cannot declare a global array with a variable size (VLA). Use a compile time constant.
// int const N = 10;
#define N 10
int D[N+2][N+2];
// int const nCircle = 4;
#define nCircle 4
int center[nCircle][2] = {{1, 1}, {N, N}, {N, 1}, {1, N}};
double radius[nCircle] = {2, 2, 2, 2};
Alternatively use C99, and declare D[] and center[] inside main(). Code could use another method to use data in eval() like eval(N, D, nCircle, center, radius)
int main() {
int const N = 10;
int D[N+2][N+2] = {0}; // Initialize D
int const nCircle = 4;
int center[nCircle][2] = {{1, 1}, {N, N}, {N, 1}, {1, N}};
double radius[nCircle] = {2, 2, 2, 2};