Как переместить на месте растровое изображение в C ++ - PullRequest
0 голосов
/ 16 октября 2018

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

Исходные растровые изображения представлены в виде 1-пиксельного массива в формате ARGB.

void transpose(uint8_t* buffer, const uint32_t width, const uint32_t height)
{
    const size_t stride = width * sizeof(uint32_t);

    for (uint32_t i = 0; i < height; i++)
    {
        uint32_t* row = (uint32_t*)(buffer + (stride * i));
        uint8_t* section = buffer + (i * sizeof(uint32_t));

        for (uint32_t j = i + 1; j < height; j++)
        {
            const uint32_t tmp = row[j];
            row[j] = *((uint32_t*)(section + (stride * j)));
            *((uint32_t*)(section + (stride * j))) = tmp;
        }
    }
}

enter image description here

ОБНОВЛЕНИЕ :

Чтобы прояснить ситуацию и избежать недоразумений, поскольку некоторые люди думают, что это просто вопрос поворота изображения, Транспонирование изображение состоит из 2 преобразований: 1) перевернуть по горизонтали 2) повернуть на 90 против часовой стрелки.(Как показано на примере изображения, см. Направления стрелок )

Ответы [ 3 ]

0 голосов
/ 16 октября 2018

Я думаю, что проблема сложнее, чем вы думаете, и это не просто случай замены пикселей на x, y с пикселями на y, x.Если вы рассматриваете изображение размером 3 * 7 пикселей, в котором я пометил пиксели a - u:

abcdefg
hijklmn
opqrstu

Поворот этого изображения дает:

aho
bip
cjq
dkr
els
fmt
gnu

Поворот обоихизображения в одномерном массиве дают:

abcdefghijklmnopqrstu

ahobipcjqdkrelsfmtgnu

Обратите внимание, что b переместился в положение d, но был заменен на h.

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

Из-за сложности задачи может оказаться быстрее создать временный буфер, повернуть его в этот буфер и затем скопировать обратно.так как это может привести к меньшему количеству копий (2 на пиксель), чем алгоритм на месте, который вы придумали.

0 голосов
/ 16 октября 2018

Обратите внимание, что транспонирование матрицы на месте не является тривиальным, когда N!=M.См. Например здесь для получения подробной информации.

Причина в том, что когда N=M, вы можете просто перебрать половину матрицы и поменять местами элементы.Когда N!=M это не так.

Для иллюстрации рассмотрим более простой случай:

Сначала 2-мерное представление для 1d данных:

struct my2dview {
    std::vector<int>& data;
    int width,height;
    my2dview(std::vector<int>& data,int width,int height):data(data),width(width),height(height){}
    int operator()(int x,int y) const { return data[x*width + y]; }
    int& operator()(int x,int y){ return data[x*width + y]; }
    my2dview get_transposed() { return my2dview(data,height,width);}
};


std::ostream& operator<<(std::ostream& out, const my2dview& x){
    for (int h=0;h<x.height;++h){
        for (int w=0;w<x.width;++w){
            out << x(h,w) << " ";
        }
        out << "\n";
    }
    return out;
}

Теперь транспонирование, которое будет работать для N=M:

my2dview broken_transpose(my2dview x){
    auto res = x.get_transposed();
    for (int i=0;i<x.height;++i){
        for (int j=0;j<x.width;++j){
            res(j,i) = x(i,j);
        }
    }
    return res;
}

Использование его для некоторой небольшой матрицы

int main() {
    std::vector<int> x{1,2,3,4,5,6};
    auto v = my2dview(x,2,3);
    std::cout << v << '\n';
    std::cout << v.get_transposed() << '\n';
    auto v2 = broken_transpose(v);
    std::cout << v2;
}

printints

1 2
3 4
5 6

1 2 3
4 5 6

1 3 2
2 2 6

Вывод: подход наивных элементов обмена не работает для неквадратных матриц.

На самом деле этот ответ перефразирует ответ @Alan Birtles.Я чувствовал, что его

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

, просто чтобы прийтик такому же выводу;).

0 голосов
/ 16 октября 2018

В основном эквивалентный код, который легче отлаживать:

inline uint32_t * addr(uint8_t* buffer, const uint32_t width, uint32_t i, uint32_t j) {
    uint32_t * tmp = buffer;
    return tmp+i*width+j;
}

void transpose(uint8_t* buffer, const uint32_t width, const uint32_t height) {
    for (uint32_t i = 0; i < min(width,height); i++) {
        for (uint32_t j = 0; j < i; j++) {
            uint32_t * a = addr(buffer, width, i, j);
            uint32_t * b = addr(buffer, width, j, i);
            const uint32_t tmp = *a;
            *a = *b;
            *b = tmp;
        }
    }
}

Если это не работает правильно, возможно, ему нужно знать не только ширину картинки, но и ширинуосновного буфера.Это только переворачивает квадратную часть в верхнем левом углу, потребуется больше работы для неквадратных растровых изображений.(или просто добавьте все в квадрат перед использованием ...)

...