使用OpenCV转换图像内容

时间:2013-09-28 14:38:28

标签: c++ opencv

从图像开始,我想将其内容移至10个像素的顶部,而不更改大小并在底部填充黑色的子图像width x 10

例如,原文:

Original

转移了:

Shifted

是否有使用OpenCV直接执行此操作的功能?

10 个答案:

答案 0 :(得分:30)

您可以简单地使用仿射变换转换矩阵(基本上用于转换点)。具有适当变换矩阵的cv::warpAffine()可以解决问题。

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

其中: tx 在图像x轴上移位, ty 在图像y轴上移位, 图像中的每个像素都会像这样移动。

您可以使用此函数返回翻译矩阵。 (这对您来说可能是不必要的)但它会根据offsetxoffsety参数移动图像。

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

然后你的图像会根据你的意愿移动。

答案 1 :(得分: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)));

答案 2 :(得分:4)

这是我根据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;
}

答案 3 :(得分:3)

  
    

是否有使用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));

答案 4 :(得分:2)

h, w = image.shape     # for gray image
shift = 100          # any legal number 0 < x < h

img[:h-shift, :] = img[shift:, :]
img[h-shift:, :] = 0

答案 5 :(得分: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));

它来自我自己的工作代码,但是一些变量发生了变化,如果它不能编译,很可能只是一件小事需要改变 - 但是你得到了这个想法。 abs 功能......

答案 6 :(得分:1)

this link可能对这个问题有帮助,谢谢

import cv2
import numpy as np
img = cv2.imread('images/input.jpg')
num_rows, num_cols = img.shape[:2]   

translation_matrix = np.float32([ [1,0,70], [0,1,110] ])   
img_translation = cv2.warpAffine(img, translation_matrix, (num_cols, num_rows))   
cv2.imshow('Translation', img_translation)    
cv2.waitKey()

tx ty 可以分别控制x和y方向上的移位像素。

enter image description here

答案 7 :(得分:0)

您可以使用简单的2d滤镜/卷积来实现目标:

直接从the OpenCV documentation开始。您需要使用具有高度(desired_displacement_y * 2 + 1)和宽度(desired_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 );

注意filter2D中的BORDER_CONSTANT!您现在应该运行该示例,并使图片每0.5秒向上滚动一个像素。您还可以使用绘图方法绘制黑色像素。

有关其原因,请参阅Wikipedia

答案 8 :(得分: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的解决方案快了几个数量级。 (但这当然可能与你的情况完全无关。)

答案 9 :(得分:0)

由于当前没有Python解决方案,而Google搜索使用Python来移动图像的操作将带您到此页面,因此这里是使用np.roll()

的Python解决方案

沿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()