C# EmguCV 调整垫子大小但保持 bounds/resolution

C# EmguCV Resize Mat but keep bounds/resolution

我已经尝试了很多东西,但是我所有的尝试都失败了。 我需要将灰色图像 (2560x1440) 调整为更低或更高的分辨率,然后我需要将边界设置为原始尺寸 (2560x1440),但将调整后的图像保持在中心。

我正在使用 EmguCV 4.3 和 Mat,我尝试了很多方法并在 Mat 构造函数和 copyTo 上使用 ROI,但没有任何效果,它总是使用调整后的边界设置新 Mat

所需示例:

源图片:(2560x1440)

50% 调整大小,但保持与源 (2560x1440) 相同的边界

300% 调整大小,但保持与源 (2560x1440) 相同的边界

我觉得应该有更优雅的方法来做到这一点,但是,我提供了两种扩展方法:

static void CopyToCenter(this Image<Gray,byte> imgScr, Image<Gray, byte> imgDst)
{
    int dx = (imgScr.Cols - imgDst.Cols) / 2;
    int dy = (imgScr.Rows - imgDst.Rows) / 2;

    byte[,,] scrData = imgScr.Data;
    byte[,,] dstData = imgDst.Data;
    for(int v = 0; v < imgDst.Rows; v++)
    {
        for (int u = 0; u < imgDst.Cols; u++)
        {
            dstData[v,u, 0] = scrData[v + dy, u + dx, 0];
        }
    }
}

static void CopyFromCenter(this Image<Gray, byte> imgDst, Image<Gray, byte> imgScr)
{
    int dx = (imgDst.Cols - imgScr.Cols) / 2;
    int dy = (imgDst.Rows - imgScr.Rows) / 2;

    byte[,,] scrData = imgScr.Data;
    byte[,,] dstData = imgDst.Data;
    for (int v = 0; v < imgScr.Rows; v++)
    {
        for (int u = 0; u < imgScr.Cols; u++)
        {
            dstData[v + dy, u + dx, 0] = scrData[v, u, 0];
        }
    }
}

哪个可以这样使用:

static void Main(string[] args)
{
    double scaleFactor = 0.8;
    Image<Gray, byte> orginalImage = new Image<Gray, byte>("Bmv60.png");
    Image<Gray, byte> scaledImage = orginalImage.Resize(scaleFactor, Inter.Linear);
    Image<Gray, byte> outputImage = new Image<Gray, byte>(orginalImage.Size);

    if(scaleFactor > 1)
    {
        scaledImage.CopyToCenter(outputImage);
    }
    else
    {
        outputImage.CopyFromCenter(scaledImage);
    }           
}

您没有要求特定的语言,所以我希望 C# 有用。

使用 WarpAffine 对图像应用仿射变换。使用变换矩阵,您可以应用缩放和平移变换。也支持旋转,但我的示例中未涵盖。翻译值也可以是负数。

WrapAffine 方法有更多参数供您使用。

    public void Test()
    {
    
        var img = new Mat("Bmv60.png", ImreadModes.Grayscale);
    
        Mat upscaled = GetContentScaled(img, 2.0, 0.5, 0, 0);
        upscaled.Save("scaled1.png");
    
        Mat downscaled = GetContentScaled(img, 0.5, 0.5, 0, 0);
        downscaled.Save("scaled2.png");
    }
    
    private Mat GetContentScaled(Mat src, double xScale, double yScale, double xTrans, double yTrans, Inter interpolation = Inter.Linear)
    {
        var dst = new Mat(src.Size, src.Depth, src.NumberOfChannels);
        var translateTransform = new Matrix<double>(2, 3)
        {
            [0, 0] = xScale, // xScale
            [1, 1] = yScale, // yScale
            [0, 2] = xTrans + (src.Width - src.Width * xScale) / 2.0, //x translation + compensation of  x scaling
            [1, 2] = yTrans + (src.Height - src.Height * yScale) / 2.0 // y translation + compensation of y scaling
        };
        CvInvoke.WarpAffine(src, dst, translateTransform, dst.Size, interpolation);
    
        return dst;
    }