2013-09-28 2 views
22

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

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

Original

И смещенная:

Shifted

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

ответ

25

Есть ли функция для выполнения этой операции с помощью 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))); 
+0

Это немного неприятный трюк. Он работает, но есть ненужное создание «нулевого изображения» и копирования. Я верю в свое решение, используя [аффинное преобразование] (http://stackoverflow.com/a/26766505/2740907), более чистая и эффективная. –

+8

@pajus_cz, «нулевое изображение» будет создано в любом случае, даже если вы его не создаете сами. Кроме того, copyTo выполняет простую операцию memcopy, которая намного быстрее, чем все сложные операции, выполняемые wrapAffine. – user2983637

+0

Спасибо! Второй результат быстрее, чем wrapAffine для меня. – dhiga

0

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

взятых прямо из the OpenCV documentation. Вам нужно будет фильтровать с ядром с высотой (желаемое_значение_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.

+0

Творческий ответ, но интенсивный процессор. Вместо этого используйте метод сдвига. – TimZaman

4

Вот функция, я написал, основываясь на ответе Зо Лин, чтобы сделать кадр/смещение изображения в любом направлении на любое количество пиксельных строк или столбцов:

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

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

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

где: ТХ является сдвиг в изображении оси х, ти является смещение оси изображения у, Каждый пиксель в изображении будет смещена в этом роде.

Вы можете использовать эту функцию, которая возвращает матрицу перевода.(Это, вероятно, не нужно для вас). Но это изменит изображение на основе параметров 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 trans_mat; 
} 

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

translateImg(image,0,-10); 

И тогда ваш образ будет смещен, как вы хотите.

+0

Не могли бы вы объяснить, что говорит 'Mat_ (2,3) << 1'? – locke14

+1

Это не просто 'Mat_ (2,3) << 1. Это целое выражение: 'Mat_ (2,3) << 1, 0, offsetx, 0, 1, offsety', которые вставляют значения в матрицу. Таким образом, значения в 'trans_mat' будут' 1,0, offsetx' в первой строке и '0, 1, offsety' во второй строке. Как показано в матрице 'M' в исходном сообщении. –

+1

Творческий ответ, но интенсивность процессора по сравнению с другими решениями. – TimZaman

1

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

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

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

0

Я сначала пробовал с pajus_cz's 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. (Но это, конечно, может быть совершенно неуместным в вашем случае.)

2

Есть функция для выполнения этой операции непосредственно с 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)); 
Смежные вопросы