He intentado muchas cosas, pero todos mis intentos fallan. Necesito cambiar el tamaño de una imagen gris (2560x1440) a una resolución más baja o más alta, luego necesito establecer los límites al tamaño original (2560x1440) pero mantener la imagen redimensionada en el centro.

Estoy usando Emgu CV 4.3 y Mat, probé muchos enfoques y uso de ROI en el constructor de Mat y un copyTo, pero nada funciona, siempre establece un nuevo Mat con los límites redimensionados

Ejemplo de lo requerido:

Imagen de origen: (2560x1440) source

50% redimensionado, pero mantiene los mismos límites que la fuente (2560x1440) x0.5

300% redimensionado, pero mantiene los mismos límites que la fuente (2560x1440) 300

0
Tiago Conceição 23 jun. 2020 a las 01:08

2 respuestas

La mejor respuesta

Use WarpAffine para aplicar una transformación afín a la imagen. Usando la matriz de transformación puede aplicar escala y traducir la transformación. La rotación también es compatible pero no está cubierta en mi ejemplo. Los valores de traducción también pueden ser negativos.

El método WrapAffine tiene algunos parámetros más con los que puedes jugar.

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;
}
1
Quergo 23 jun. 2020 a las 21:01

Siento que debería haber una forma más elegante de hacer esto, sin embargo, ofrezco dos métodos de extensión:

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

Que puede usarlos así:

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

No solicitó un idioma específico, por lo que espero que C # sea útil.

1
George Kerwood 23 jun. 2020 a las 14:27