1

I have this part of code working in C++

Mat mapFrame5(Size(321,262), CV_16UC2);
for (int y = 0; y < mapFrame5.rows; y++) {
    for (int x = 0; x < mapFrame5.cols; x++) {
        mapFrame5.at<Vec2w>(y, x) = Vec2w(y, x);
        cout<<mapFrame5.at<Vec2w>(y,x);
    }
}

I have a hard time finding if there is equivalent of this expression in Python:

mapFrame5.at<Vec2w>(y, x) = Vec2w(y, x);

I tried following as suggested:

testArr2 = np.zeros([262,321], np.uint16)

y,yy = 0,0
byteCount = 0
while yy < 262:
    x,xx = 0,0
    while xx < 321:
        testArr2[yy,xx] = [yy,xx]
        xx+=1
        x+=1        
        byteCount+=1
    yy+=1
    y+=1 

But it gives me only this error:

builtins.TypeError: int() argument must be a string, a bytes-like object or a real number, not 'list'

For clearence I'm trying to save y,x values to little endian binary file.

Example:

y = 0

0 0 0 1 0 2 0 3 ... 0 320

y = 261

261 0 261 1 261 2 ... 261 320

C++ file gives me exacly 336408 bytes

4
  • It could help if you'd explain in plain words what do you want to achieve with your expression for non C++ readers... Commented Nov 29, 2021 at 15:01
  • 1
    opencv Mat in python are just numpy arrays. You code can just be mapFrame5[y,x] = [y,x] in python. Commented Nov 29, 2021 at 15:20
  • @QuangHoang Edited post, I can't get your solution to work Commented Nov 29, 2021 at 15:56
  • 1
    You need to make the array 2 channel - np.zeros([262,321,2], np.uint16).
    – Dan Mašek
    Commented Nov 29, 2021 at 16:32

1 Answer 1

3

The naive approach would be to just transcribe the algorithm to Python:

def gen_grid_1(rows, cols):
    result = np.zeros((rows, cols, 2), np.uint16)
    for r in range(rows):
        for c in range(cols):
            result[r,c,:] = [r, c]
    return result

Example output for 3 rows and 5 columns:

[[[0 0]
  [0 1]
  [0 2]
  [0 3]
  [0 4]]

 [[1 0]
  [1 1]
  [1 2]
  [1 3]
  [1 4]]

 [[2 0]
  [2 1]
  [2 2]
  [2 3]
  [2 4]]]

However, this approach has a serious drawback -- it will be very slow, due to Python interpreter overhead -- for your example 321x262 array, this takes almost 1 second to complete.


A better approach is to restate the goal of the algorithm, and reimplement using optimized functions provided by Numpy.

What we want to generate is a 2 channel array of 16-bit unsigned integers, where the first channel of each element holds its row index, and the second channel holds the column index.

This sounds very close to what the numpy.meshgrid function does: "Return coordinate matrices from coordinate vectors."

The only catch is that it returns 2 individual arrays. We can simply use numpy.dstack to combine them into one with the channels in desired order.

def gen_grid_2(rows, cols):
    cc, rr = np.meshgrid(np.arange(cols, dtype=np.uint16), np.arange(rows, dtype=np.uint16))
    return np.dstack([rr,cc])

The output of this function is identical to the first, but it runs in approx. 2 milliseconds (i.e. ~500x faster than the naive approach).


Full script with timing comparisons:

import numpy as np

ROWS = 262
COLS = 321

def gen_grid_1(rows, cols):
    result = np.zeros((rows, cols, 2), np.uint16)
    for r in range(rows):
        for c in range(cols):
            result[r,c,:] = [r, c]
    return result

def gen_grid_2(rows, cols):
    cc, rr = np.meshgrid(np.arange(cols, dtype=np.uint16), np.arange(rows, dtype=np.uint16))
    return np.dstack([rr,cc])


assert(np.array_equal(gen_grid_1(ROWS, COLS), gen_grid_2(ROWS, COLS)))


import timeit
print(timeit.timeit('r1 = gen_grid_1(ROWS, COLS)'
    , number=10
    , setup="from __main__ import gen_grid_1, ROWS, COLS"))
print(timeit.timeit('r1 = gen_grid_2(ROWS, COLS)'
    , number=10
    , setup="from __main__ import gen_grid_2, ROWS, COLS"))
1
  • 1
    Yes! This is exactly what I needed, thank you! I though so there may be a numpy function for it. Commented Nov 29, 2021 at 18:39

Not the answer you're looking for? Browse other questions tagged or ask your own question.