Перейти к содержимому
Compvision.ru
Smorodov

Масштабирование при помощи сплайнов Catmul-Rom

Recommended Posts

Наваял ресайзер на основе сплайнов Catmul-Rom, мне кажется результат выглядит лучше, чем масштабирование OpenCV-шным ресайзом, с любыми опциями. Для цвета пока не делал, работает только с серыми одноканальными.

Эта функция Scale2Times удваивает исходный размер изображения.

Для произвольного масштаба, можно сначала масштабировать до размера, кратного степени 2, я затем линейной интерполяцией уменьшить размер до необходимого.

post-1-0-49029100-1342695255_thumb.png


#include <iostream>
#include <vector>
#include <stdio.h>
#include <stdarg.h>
#include "opencv2/core/core.hpp"
#include "opencv2/core/gpumat.hpp"
#include "opencv2/core/opengl_interop.hpp"
#include "opencv2/gpu/gpu.hpp"
#include "opencv2/ml/ml.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/contrib/contrib.hpp"
#include "opencv2/video/tracking.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/nonfree/nonfree.hpp"
#include "fstream"
#include "iostream"
using namespace std;
using namespace cv;

//-----------------------------------------------------------------------------------------------------
// Catmul-rom сплайн (полно разных вариантов в инете). Catmul-rom отличается тем, что проходит через
// все узловые точки, то есть, не происходит искажения существующей информации.
//-----------------------------------------------------------------------------------------------------
// Берем 2 точки, находим, что между p1 и p2, p0 и p3 нужны для нахождения касательных
// на краях. Параметр t - меняется от 0 до 1 (0 - мы в точке p1, 1 - в точке p2)
//-----------------------------------------------------------------------------------------------------
void PointOnCurve(Point2f &out, float t, Point2f p0, Point2f p1, Point2f p2, Point2f p3)
{
float t2 = t * t;
float t3 = t2 * t;
out.x = 0.5f * ( ( 2.0f * p1.x ) + ( -p0.x + p2.x ) * t +
( 2.0f * p0.x - 5.0f * p1.x + 4 * p2.x - p3.x ) * t2 +
( -p0.x + 3.0f * p1.x - 3.0f * p2.x + p3.x ) * t3 );
out.y = 0.5f * ( ( 2.0f * p1.y ) + ( -p0.y + p2.y ) * t +
( 2.0f * p0.y - 5.0f * p1.y + 4 * p2.y - p3.y ) * t2 +
( -p0.y + 3.0f * p1.y - 3.0f * p2.y + p3.y ) * t3 );
}
//-----------------------------------------------------------------------------------------------------
// Интерполяция патча 4х4 точки
//
// S * S * S * S
// * * * * * * *
// S * S * S * S
// * * * * * * *
// S * S * S * S
// * * * * * * *
// S * S * S * S
//
// S- точки исходного изображения
//
// Вначале последовательно посчитаем два средних столбца, и найдем точки D
//
// S * 1 * 2 * S
// * * * * * * *
// S * 1 * 2 * S
// * * D * D * *
// S * 1 * 2 * S
// * * * * * * *
// S * 1 * 2 * S
//
// Затем последовательно посчитаем две средних строки, и найдем точки F
//
// S * S * S * S
// * * * * * * *
// 3 * 3 F 3 * 3
// * * D * D * *
// 4 * 4 F 4 * 4
// * * * * * * *
// S * S * S * S
//
// И последовательно посчитаем две диагонали, и после усреднения c учетом соседей, и найдем точку С
//
// 1 * S * S * 2
// * * * * * * *
// S * 1 F 2 * S
// * * D C D * *
// S * 2 F 1 * S
// * * * * * * *
// 2 * S * S * 1
//-----------------------------------------------------------------------------------------------------
void PointOnSurface(Mat& src,Mat& dst)
{
float t=0.5;
Point2f out;
dst=Mat(3,3,CV_32FC1);
// Угловые точки результата совпадают с точками центральной ячейки исходного патча
dst.at<float>(0,0)=src.at<float>(1,1);
dst.at<float>(2,0)=src.at<float>(2,1);

dst.at<float>(0,2)=src.at<float>(1,2);
dst.at<float>(2,2)=src.at<float>(2,2);

Point2f p0;
Point2f p1;
Point2f p2;
Point2f p3;
// по столбцам (2 средних) x = rows, y = value
p0.x=0;p0.y=src.at<float>(0,1);
p1.x=1;p1.y=src.at<float>(1,1);
p2.x=2;p2.y=src.at<float>(2,1);
p3.x=3;p3.y=src.at<float>(3,1);

PointOnCurve(out,t,p0,p1,p2,p3);
dst.at<float>(1,0)=out.y;

// по столбцам (2 средних) x = rows, y = value
p0.x=0;p0.y=src.at<float>(0,2);
p1.x=1;p1.y=src.at<float>(1,2);
p2.x=2;p2.y=src.at<float>(2,2);
p3.x=3;p3.y=src.at<float>(3,2);

PointOnCurve(out,t,p0,p1,p2,p3);
dst.at<float>(1,2)=out.y;

// по строкам (2 средних) x = cols, y = value
p0.x=0;p0.y=src.at<float>(1,0);
p1.x=1;p1.y=src.at<float>(1,1);
p2.x=2;p2.y=src.at<float>(1,2);
p3.x=3;p3.y=src.at<float>(1,3);


PointOnCurve(out,t,p0,p1,p2,p3);
dst.at<float>(0,1)=out.y;

// по строкам (2 средних) x = cols, y = value
p0.x=0;p0.y=src.at<float>(2,0);
p1.x=1;p1.y=src.at<float>(2,1);
p2.x=2;p2.y=src.at<float>(2,2);
p3.x=3;p3.y=src.at<float>(2,3);

PointOnCurve(out,t,p0,p1,p2,p3);
dst.at<float>(2,1)=out.y;

// Диагонали

// Диагональ 1
p0.x=0;p0.y=src.at<float>(0,0);
p1.x=1;p1.y=src.at<float>(1,1);
p2.x=2;p2.y=src.at<float>(2,2);
p3.x=3;p3.y=src.at<float>(3,3);


PointOnCurve(out,t,p0,p1,p2,p3);
float d1=out.y;

// Диагональ 2
p0.x=0;p0.y=src.at<float>(3,0);
p1.x=1;p1.y=src.at<float>(2,1);
p2.x=2;p2.y=src.at<float>(1,2);
p3.x=3;p3.y=src.at<float>(0,3);

PointOnCurve(out,t,p0,p1,p2,p3);
float d2=out.y;

// Усредняем
dst.at<float>(1,1)=1.0/6.0*(d1+d2+dst.at<float>(0,1)+dst.at<float>(1,0)+dst.at<float>(1,2)+dst.at<float>(2,1));
}
//-----------------------------------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------
void Scale2Times(Mat& src_img,Mat &dstImg)
{
Mat imgf,img;
Mat dst;
Mat src;
src_img.convertTo(imgf,CV_32FC1,1.0/255.0);

cv::copyMakeBorder(imgf,img,1,1,1,1,cv::BORDER_REFLECT);

dstImg=Mat(src_img.rows*2,src_img.cols*2,CV_32FC1);

for(int i=0;i<img.rows-4;i++)
{
for(int j=0;j<img.cols-4;j++)
{
img(Rect(j,i,4,4)).copyTo(src);
PointOnSurface(src,dst);
dst.copyTo(dstImg(Rect(2*j+1,2*i+1,3,3)));
}
}
dstImg=dstImg(Rect(0,0,dstImg.cols-2,dstImg.rows-2)).clone();
}
//-----------------------------------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------------------------------
int main( int argc, char** argv )
{
namedWindow("Src");
namedWindow("cvResize");
namedWindow("Catmul-Rom");
Mat Img=imread("C:\\ImagesForTest\\1.tiff",0);
imshow("Src",Img);
Mat dstImg;
Scale2Times(Img,dstImg);
imshow("Catmul-Rom",dstImg);

Mat ImgLin(Img.rows*2,Img.cols*2,CV_8UC1);
cv::resize(Img,ImgLin,Size(Img.cols*2,Img.rows*2),INTER_CUBIC);
imshow("cvResize",ImgLin);

waitKey(0);
//getchar();

return 0;
}
[/code]

Catmul-Rom.cpp

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создайте учётную запись или войдите для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать учётную запись

Зарегистрируйтесь для создания учётной записи. Это просто!

Зарегистрировать учётную запись

Войти

Уже зарегистрированы? Войдите здесь.

Войти сейчас


  • Сейчас на странице   0 пользователей

    Нет пользователей, просматривающих эту страницу

×