Подтвердить что ты не робот

Сдвинуть изображение с помощью OpenCV

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

Например, оригинал:

Original

И сдвинутый:

Shifted

Есть ли функция, выполняющая непосредственно эту операцию с помощью OpenCV?

4b9b3361

Ответ 1

Есть ли функция, выполняющая непосредственно эту операцию с помощью OpenCV?

http://code.opencv.org/issues/2299

или вы сделаете это

    cv::Mat out = cv::Mat::zeros(frame.size(), frame.type());
    frame(cv::Rect(0,10, frame.cols,frame.rows-10)).copyTo(out(cv::Rect(0,0,frame.cols,frame.rows-10)));

Ответ 2

Вы можете просто использовать матрицу перевода аффинного преобразования (в основном, для смещения точек). cv::warpAffine() с правильной матрицей преобразования сделает cv::warpAffine() дело.

TranslationMatrix [1,0,tx ; 0,1,ty]

где: tx - смещение по оси x изображения, ty - смещение по оси y изображения, каждый отдельный пиксель в изображении будет смещен таким образом.

Вы можете использовать эту функцию, которая возвращает матрицу перевода. (Это, вероятно, вам не нужно) Но это сместит изображение на offsety параметров offsetx и offsety.

Mat translateImg(Mat &img, int offsetx, int offsety){
    Mat trans_mat = (Mat_<double>(2,3) << 1, 0, offsetx, 0, 1, offsety);
    warpAffine(img,img,trans_mat,img.size());
    return img;
}

В вашем случае - вы хотите сместить изображение на 10 пикселей вверх, вы звоните:

translateImg(image,0,-10);

И тогда ваш образ будет смещен по вашему желанию.

Ответ 3

Вот функция, которую я написал на основе ответа Zaw Lin, чтобы сделать сдвиг кадра/изображения в любом направлении любым количеством строк или столбцов пикселей:

enum Direction{
    ShiftUp=1, ShiftRight, ShiftDown, ShiftLeft
   };

cv::Mat shiftFrame(cv::Mat frame, int pixels, Direction direction)
{
    //create a same sized temporary Mat with all the pixels flagged as invalid (-1)
    cv::Mat temp = cv::Mat::zeros(frame.size(), frame.type());

    switch (direction)
    {
    case(ShiftUp) :
        frame(cv::Rect(0, pixels, frame.cols, frame.rows - pixels)).copyTo(temp(cv::Rect(0, 0, temp.cols, temp.rows - pixels)));
        break;
    case(ShiftRight) :
        frame(cv::Rect(0, 0, frame.cols - pixels, frame.rows)).copyTo(temp(cv::Rect(pixels, 0, frame.cols - pixels, frame.rows)));
        break;
    case(ShiftDown) :
        frame(cv::Rect(0, 0, frame.cols, frame.rows - pixels)).copyTo(temp(cv::Rect(0, pixels, frame.cols, frame.rows - pixels)));
        break;
    case(ShiftLeft) :
        frame(cv::Rect(pixels, 0, frame.cols - pixels, frame.rows)).copyTo(temp(cv::Rect(0, 0, frame.cols - pixels, frame.rows)));
        break;
    default:
        std::cout << "Shift direction is not set properly" << std::endl;
    }

    return temp;
}

Ответ 4

Есть ли функция, выполняющая непосредственно эту операцию с помощью OpenCV?

http://code.opencv.org/issues/2299

или вы сделаете это

  cv::Mat out = cv::Mat::zeros(frame.size(), frame.type());
  frame(cv::Rect(0,10,
  frame.cols,frame.rows-10)).copyTo(out(cv::Rect(0,0,frame.cols,frame.rows-10)));

Только вышеприведенный код может использоваться для перехода на одну сторону (влево и вверх). Ниже приведен код расширенной версии кода, который можно использовать для перехода во все направления.

int shiftCol = 10;
int shiftRow = 10;

Rect source = cv::Rect(max(0,-shiftCol),max(0,-shiftRow), frame.cols-abs(shiftCol),frame.rows-abs(shiftRow));

Rect target = cv::Rect(max(0,shiftCol),max(0,shiftRow),frame.cols-abs(shiftCol),frame.rows-abs(shiftRow));

frame(source).copyTo(out(target));

Ответ 5

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

using namespace cv;
//and whatever header 'abs' requires...

Mat offsetImageWithPadding(const Mat& originalImage, int offsetX, int offsetY, Scalar backgroundColour){
        cv::Mat padded = Mat(originalImage.rows + 2 * abs(offsetY), originalImage.cols + 2 * abs(offsetX), CV_8UC3, backgroundColour);
        originalImage.copyTo(padded(Rect(abs(offsetX), abs(offsetY), originalImage.cols, originalImage.rows)));
        return Mat(padded,Rect(abs(offsetX) + offsetX, abs(offsetY) + offsetY, originalImage.cols, originalImage.rows));
}

//example use with black borders along the right hand side and top:
Mat offsetImage = offsetImageWithPadding(originalImage, -10, 6, Scalar(0,0,0));

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

Ответ 6

Вы можете использовать простой 2d фильтр/свертку для достижения своей цели:

Взято прямо из документации OpenCV. Вам нужно будет фильтровать с ядром с высотой (желаемое_значение_y * 2 + 1) и шириной (wish_displacement_x * 2 + 1).

Затем вам нужно установить ядро ​​ко всем нулям, за исключением относительной позиции пикселя, из которой вы хотите скопировать. Поэтому, если ваш центр ядра равен (0,0), вы должны установить (10,0) в 1 для смещения 10 пикселей.

Возьмите образец кода с веб-сайта и замените код ядра посередине следующим образом:

  /// Update kernel size for a normalized box filter
  kernel_size = 1 + ind * 2; //Center pixel plus displacement diameter (=radius * 2)
  kernel = Mat::zeros( kernel_size, kernel_size, CV_32F );
  kernel.at<float>(ind * 2, ind) = 1.0f; // Indices are zero-based, not relative

  /// Apply filter
  filter2D(src, dst, ddepth , kernel, anchor, delta, BORDER_CONSTANT );

Обратите внимание на BORDER_CONSTANT в filter2D! Теперь вы должны запустить пример и прокрутить изображение на один пиксель каждые 0,5 секунды. Вы также можете рисовать черные пиксели с помощью методов рисования.

О том, почему это работает, см. Wikipedia.

Ответ 7

Сначала я попробовал pajus_cz answer, но на практике это было довольно медленно. Кроме того, я не могу позволить себе сделать временную копию, поэтому я придумал следующее:

void translateY(cv::Mat& image, int yOffset)
{
    int validHeight = std::max(image.rows - abs(yOffset), 0);
    int firstSourceRow = std::max(-yOffset, 0);
    int firstDestinationRow = std::max(yOffset, 0);

    memmove(image.ptr(firstDestinationRow),
            image.ptr(firstSourceRow),
            validHeight * image.step);
}

Он на порядок быстрее, чем решение на основе warpAffine. (Но это, конечно, может быть совершенно неуместным в вашем случае.)

Ответ 8

Поскольку в настоящее время нет решения Python и в поиске Google для сдвига изображения с использованием Python вы попадаете на эту страницу, здесь решение Python с использованием np.roll()


Сдвиг по оси X

enter image description here

import cv2
import numpy as np

image = cv2.imread('1.jpg')
shift = 40

for i in range(image.shape[1] -1, image.shape[1] - shift, -1):
    image = np.roll(image, -1, axis=1)
    image[:, -1] = 0

cv2.imshow('image', image)
cv2.waitKey()

Смещение по оси Y

enter image description here

import cv2
import numpy as np

image = cv2.imread('1.jpg')
shift = 40

for i in range(image.shape[0] -1, image.shape[0] - shift, -1):
    image = np.roll(image, -1, axis=0)
    image[-1, :] = 0

cv2.imshow('image', image)
cv2.waitKey()