Home > database >  How to use Vec2w in Opencv Python
How to use Vec2w in Opencv Python

Time:11-30

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

CodePudding user response:

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"))
  • Related