简体   繁体   English

使用锯齿形扫描将 8x8 矩阵转换为展平向量

[英]Convert 8x8 Matrix into flatten vector using zigzag scan

So I need to convert an opencv mat that is 8x8 into a flattened vector using a zig zag scan as shown in this image.因此,我需要使用 zig zag 扫描将 8x8 的 opencv mat 转换为扁平矢量,如图所示。

之字形解释

I understand what it is supposed to be doing and I think I have gotten the first half implementation down but I am receiving an error when I am trying to set the value to the vector.我明白它应该做什么,我想我已经完成了前半部分的实现,但是当我尝试将值设置为向量时收到错误。

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));
    }
}

At this point, I am just struggling to figure this portion out and any advice would mean a ton!在这一点上,我只是在努力弄清楚这部分,任何建议都意味着一吨! return output;返回输出; } }

Your output vector stores float , so why do you try pushing a pointer to cv::Mat there?您的输出向量存储float ,那么您为什么要尝试将指针推到cv::Mat那里呢?

If you have 8x8 matrix of float, just use .at<float>(y,x) method to access one float value of input matrix.如果您有 8x8 的浮点矩阵,只需使用.at<float>(y,x)方法来访问input矩阵的一个浮点值。

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

Your approach seems that you want to use Rect as ROI and apply it on input matrix.您的方法似乎是您想使用Rect作为 ROI 并将其应用于输入矩阵。 If you want to get subregion of input Mat as 1x1 rect you could:如果您想将输入Mat区域设为 1x1 矩形,您可以:

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

Also I don't get it why you use N loops to make zigzag order, instead of array of pairs:另外我不明白为什么你使用 N 个循环来制作锯齿形顺序,而不是成对的数组:

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

then only look-up this.然后只查找这个。

In image processing every millisecond is imporant, don't waste time for fancy way of doing zigzag order.在图像处理中,每一毫秒都很重要,不要浪费时间在做锯齿形顺序的花哨方式上。

I'm very sorry not to provide the code in C/C++, but I'm pretty sure you'll be able to translate this into C/C++ without any problem, because I did not use anything specific to python:很抱歉没有提供 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

output:输出:

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

Iterate over diagonals, then over diagonal elements.遍历对角线,然后遍历对角线元素。 All you need is simple math to calculate element indices:您只需要简单的数学运算即可计算元素索引:

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
    }
}

You can force the compiler to unroll all these loops:您可以强制编译器展开所有这些循环:

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>() generates n * n calls of the given functional object without loops and branches. zigzag<n>()生成给定功能对象的n * n调用,没有循环和分支。 zigzag_indices() generates an array of pairs of indices (idea taken from rafix07 's answer). zigzag_indices()生成一组索引对(想法取自rafix07的答案)。 This function is constexpr , so that this array can be generated at compile-time.这个函数是constexpr ,所以这个数组可以在编译时生成。

Usage examples:用法示例:

// 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));
}

Demo演示

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM