Сдвинуть изображение с помощью OpenCV
Начиная с изображения, я хотел бы переместить его содержимое в верхнюю часть из 10 пикселей без изменения размера и заполнения суб изображения width x 10
снизу черным цветом.
Например, оригинал:
![Original]()
И сдвинутый:
![Shifted]()
Есть ли функция, выполняющая непосредственно эту операцию с помощью OpenCV?
Ответы
Ответ 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()