Поэтому мне нужно преобразовать мат opencv размером 8x8 в плоский вектор, используя зигзагообразное сканирование, как показано на этом изображении.

ZIG ZAG Explanation

Я понимаю, что он должен делать, и я думаю, что выполнил первую половину реализации, но я получаю сообщение об ошибке, когда пытаюсь установить значение для вектора.

std::vector<float> *ZigZagScanner::scan(cv::Mat &input) {
std::vector<float> *output = new std::vector<float>();
// TODO Traverse the input in a zigzag scan, and store the result in output
//set row and column start values to zero, set increment flag to false

 // TODO Traverse the input in a zigzag scan, and store the result in output
//set row and column start values to zero, set increment flag to false
int row, col = 0;
bool  increment = false;

//create nest for loops to traverse through the first half of the matrix in a zig zag fashion
for(int y = 1; y <= 8; ++y){
    for(int x = 0; x < y; ++x){
        //add the current row and column to the flatten vector

        //ERROR HERE
        cv::Rect rect = cv::Rect(y,x, 8, 8);
        output->push_back(new cv::Mat(input, rect));


        if(x + 1 == y){
            break;
        }

        //when the increment flag is true increase the row and decrease the column
        if(increment == true){
            ++row, --col;
        }
        else{
            --row, ++col;
        }
    }
    //if y gets to out of bounds break the loop
  if(y == 8){
    break;
  }
  //if the increment flag is true then increment the row and switch the flag, otherwise increment the column and swap the flag
  if(increment == true){
      ++row, increment = false;
  }
  else{
      ++col, increment = true;
  }
}

//update the columns and rows to the correct values to go through the second half of the matrix
if(row == 0){
    if(col == 7){
        ++row;
    }
    else{
        ++col;
        increment = true;
    }
}
else{
    if(row == 7){
        ++col;
    }
    else{
        ++row;
        increment = false;
    }
}

for(int k, j = 7; j > 0; --j){
    if(j > 8){
        k = 8;
    }
    else{
        k = j;
    }

    for(int i = 0; i < k; i++){

        //ERROR HERE AS WELL
        cv::Rect rect = cv::Rect(y,x, 8, 8);
        output->push_back(new cv::Mat(input, rect));
    }
}

На данный момент я просто изо всех сил пытаюсь понять эту часть, и любой совет будет значить тонну! возвратный вывод; }

0
kiotzu 3 Дек 2019 в 08:38
Что здесь выходной объект? Это массив, содержащий типы Mat?
 – 
Yunus Temurlenk
3 Дек 2019 в 09:18
Это вектор, удерживающий поплавки
 – 
kiotzu
3 Дек 2019 в 09:23
Для чего здесь cv::Rect?
 – 
Evg
3 Дек 2019 в 09:30
Если он содержит типы с плавающей запятой, почему вы назначили ему формат Mat?
 – 
Yunus Temurlenk
3 Дек 2019 в 09:33
В настоящее время я пытаюсь получить значения индексов, соответствующих текущей позиции, это была моя тщетная попытка.
 – 
kiotzu
3 Дек 2019 в 09:36

3 ответа

В вашем векторе вывода хранится float, так почему вы пытаетесь поместить туда указатель на cv::Mat?

Если у вас есть матрица с плавающей запятой 8x8, просто используйте метод .at<float>(y,x) для доступа к одному значению с плавающей запятой матрицы input.

output->push_back(input.at<float>(y-1,x)); // -1 because you iterate in range <1,8>

Ваш подход кажется, что вы хотите использовать Rect в качестве ROI и применить его к матрице ввода. Если вы хотите получить подобласть ввода Mat как прямоугольник 1x1, вы можете:

cv::Rect roi(x,y-1,1,1); // 1x1 matrix
output->push_back( input(roi).at<float>(0,0) );

Также я не понимаю, почему вы используете N циклов для создания зигзагообразного порядка вместо массива пар:

std::pair<int,int> zigZagOrder[64] = { {0,0},{1,0},{1,0},...};

Тогда только посмотрите это.

При обработке изображений важна каждая миллисекунда, не тратьте время на причудливые способы выполнения зигзагообразного порядка.

1
rafix07 3 Дек 2019 в 10:03

Мне очень жаль, что я не предоставил код на C / C ++, но я уверен, что вы сможете без проблем перевести это на C / C ++, потому что я не использовал ничего специфического для python:

#!/usr/bin/env python

N = 4

i, j = 0, 0

while j != (N-1) :
    print i, j

    if i == 0 and (j & 1) :
        j += 1
        continue

    if j == 0 and (i & 1) == 0:
        i += 1
        continue

    if (i ^ j) & 1 :
        i -= 1
        j += 1
        continue

    if (i ^ j) & 1 == 0 :
        i += 1
        j -= 1
        continue

while i != (N-1) or j != (N-1) :

    print i, j

    if i == (N-1) and (j & 1) :
        j += 1
        continue

    if j == (N-1) and (i & 1) == 0 :
        i += 1
        continue

    if (i ^ j) & 1 :
        i -= 1
        j += 1
        continue

    if (i ^ j) & 1 == 0 :
        i += 1
        j -= 1
        continue

print i, j  # last square

Выход:

0 0
1 0
0 1
0 2
1 1
2 0
3 0
2 1
1 2
0 3
1 3
2 2
3 1
3 2
2 3
3 3
0
lenik 3 Дек 2019 в 10:05

Обходите диагонали, затем диагональные элементы. Все, что вам нужно, это простая математика для расчета индексов элементов:

const int n = 8;
for (int diag = 0; diag < 2 * n - 1; ++diag) {
    const auto i_min = std::max(0, diag - n + 1);
    const auto i_max = i_min + std::min(diag, 2 * (n - 1) - diag);
    for (auto i = i_min; i <= i_max; ++i) {
        const auto row = diag % 2 ? i : (diag - i);
        const auto col = diag % 2 ? (diag - i) : i;

        // (row, col) is current element
    }
}

Вы можете заставить компилятор развернуть все эти циклы:

namespace impl {
template<int offset, int... is>
constexpr auto offset_sequence(std::integer_sequence<int, is...>) {
    return std::integer_sequence<int, (is + offset)...>{};
}

template<int diag, class Fn, int... is>
constexpr void zigzag2(Fn fn, std::integer_sequence<int, is...>) {
    (fn(diag % 2 ? is : diag - is, diag % 2 ? diag - is : is), ...);
}

template<int size, class Fn, int... diags>
constexpr void zigzag1(Fn fn, std::integer_sequence<int, diags...>) {
    (zigzag2<diags>(fn, offset_sequence<std::max(0, diags - size + 1)>(
        std::make_integer_sequence<int, 
            1 + std::min(diags, 2 * (size - 1) - diags)>{})), ...);
}
}

template<int size, class Fn>
constexpr void zigzag(Fn fn) {
    impl::zigzag1<size>(fn, std::make_integer_sequence<int, 2 * size - 1>{});
}

template<int size>
constexpr auto zigzag_indices() {
    std::array<std::pair<int, int>, size * size> arr{};
    auto it = arr.begin();
    zigzag<size>([&it](int x, int y) { it->first = x; it->second = y; ++it; });
    assert(it == arr.end());
    return arr;
}

zigzag<n>() генерирует n * n вызовов данного функционального объекта без циклов и ветвлений. zigzag_indices() генерирует массив пар индексов (идея взята из ответа rafix07 ). Это функция constexpr, так что этот массив может быть сгенерирован во время компиляции.

Примеры использования:

// 1.
zigzag<8>([&](int x, int y) { 
    output->push_back(input.at<float>(y, x));
});

// 2.
constexpr auto indices = zigzag_indices<8>();
for (auto i : indices) { 
    output->push_back(input.at<float>(i.second, i.first));
}

Демо

0
Evg 3 Дек 2019 в 11:21