Skip to content

Instantly share code, notes, and snippets.

@hiromiso
Created July 17, 2012 23:18
Show Gist options
  • Save hiromiso/3132785 to your computer and use it in GitHub Desktop.
Save hiromiso/3132785 to your computer and use it in GitHub Desktop.
画像の縮小テスト
#include <stdio.h>
#include <math.h>
#include <vector>
#include <opencv2/opencv.hpp>
// 最近傍法
void NearestNeighbor(const IplImage *src, IplImage *dst)
{
float wf = (double)src->width / dst->width;
float hf = (double)src->height / dst->height;
for (int y=0; y<dst->height; ++y) {
int sy = floor(hf * y + 0.5);
for (int x=0; x<dst->width; ++x) {
int sx = floor(wf*x + 0.5);
dst->imageData[y*dst->width+x] = src->imageData[sy*src->width+sx];
}
}
}
// 積分法
void AreaAveraging(const IplImage *src, IplImage *dst)
{
float ratio = (double)src->width * src->height / (dst->width * dst->height);
double ratiox = (double)src->width / dst->width;
double ratioy = (double)src->height / dst->height;
for (int y=0; y<dst->height; ++y) {
float rt = (double)y * ratioy;
float rb = (double)(y+1) * ratioy;
for (int x=0; x<dst->height; ++x) {
float rl = (double)x * ratiox;
float rr = (double)(x+1) * ratiox;
double pg(0.0);
for (int j=floor(rt); j<=floor(rb); ++j) {
float h;
if ((rt < j) && (j+1 < rb)) {
h = 1.0;
}
else if ((j <= rt) && (j+1 < rb)) {
h = 1.0 - (rt - j);
}
else if ((rt < j) && (rb <= j+1)) {
h = rb - j;
}
else {
h = rb - rt;
}
for (int i=floor(rl); i<=floor(rr); ++i) {
float w;
if ((rl < i) && (i+1 < rr)) {
w = 1.0;
}
else if ((i <= rl) && (i+1 < rr)) {
w = 1.0 - (rl - i);
}
else if ((rl < i) && (rr <= i+1)) {
w = rr - i;
}
else {
w = rr - rl;
}
pg += w * h * (unsigned char)src->imageData[j*src->width+i];
}
}
dst->imageData[y*dst->width+x] = floor(pg / ratio + 0.5);
}
}
}
// Lanczos3
inline float sinc(float p)
{
return p == 0.0 ? 1.0 : sin(p * M_PI) / (p * M_PI);
}
inline float apply(float p)
{
if (p < 0.0) {
p = -p;
}
return p < 3.0 ? sinc(p) * sinc(p / 3.0) : 0.0;
}
void makeWeight(int dw, float scale, std::vector<std::vector<float> > &weights)
{
float fwidth = 3.0;
float width = fwidth / scale;
float fscale = 1.0 / scale;
int nums = (width * 2 + 1);
weights.resize(dw + 1);
for (int i=0; i<=dw; ++i) {
weights[i].resize(nums + 2);
}
for (int i=0; i<=dw; ++i) {
float center = (float)i / scale;
int left = floor(center - width);
int right = ceil(center + width);
for (int j=left; j<=right; ++j) {
weights[i][j-left] = apply((center - j) / fscale) / fscale;
}
}
}
void Lanczos3(const IplImage *src, IplImage *dst)
{
if (dst->width == 0 || dst->height == 0) {
return;
}
IplImage *tmp;
std::vector<std::vector<float> > weights;
std::vector<int> lefts;
std::vector<int> rights;
float scale;
float width;
tmp = cvCreateImage(cvSize(dst->width, src->height), IPL_DEPTH_8U, 1);
if (src->width) {
scale = (float)dst->width / src->width;
}
else {
scale = (float)(dst->width - 1) / (src->width - 1);
}
width = 3.0 / scale;
makeWeight(dst->width, scale, weights);
lefts.resize(dst->width);
rights.resize(dst->width);
for (int x=0; x<dst->width; ++x) {
float center = (float)x / scale;
lefts[x] = floor(center - width);
rights[x] = ceil(center + width);
}
for (int y=0; y<src->height; ++y) {
for (int x=0; x<dst->width; ++x) {
int left = lefts[x];
int right = rights[x];
double s(0.0);
for (int j=left; j<=right; ++j) {
float cur = weights[x][j - left];
int n = j < 0 ? -j : j;
n = j >= src->width ? src->width - j + src->width - 1 : n;
s += cur * (unsigned char)src->imageData[y*src->width+n];
}
tmp->imageData[y*tmp->width+x] = std::min<int>(std::max<int>(s, 0), 255);
}
}
if (src->height == 1) {
scale = (float)dst->height / src->height;
}
else {
scale = (float)(dst->height - 1) / (src->height - 1);
}
width = 3.0 / scale;
makeWeight(dst->height, scale, weights);
lefts.resize(dst->height);
rights.resize(dst->height);
for (int y=0; y<dst->height; ++y) {
float center = (float)y / scale;
lefts[y] = floor(center - width);
rights[y] = ceil(center + width);
}
for (int x=0; x<dst->width; ++x) {
for (int y=0; y<dst->height; ++y) {
int left = lefts[y];
int right = rights[y];
double s(0.0);
for (int j=left; j<=right; ++j) {
float cur = weights[y][j - left];
int n = j < 0 ? -j : j;
n = j >= tmp->height ? tmp->height - j + tmp->height - 1 : n;
s += cur * (unsigned char)tmp->imageData[n*tmp->width+x];
}
dst->imageData[y*dst->width+x] = std::min<int>(std::max<int>(s, 0), 255);
}
}
}
int main(int argc, char* argv[])
{
IplImage *src;
IplImage *gry;
IplImage *dst;
src = cvLoadImage("test.jpg", CV_LOAD_IMAGE_ANYCOLOR);
gry = cvCreateImage(cvSize(src->width, src->height), IPL_DEPTH_8U, 1);
cvCvtColor(src, gry, CV_BGR2GRAY);
dst = cvCreateImage(cvSize(gry->width/5, gry->height/5), IPL_DEPTH_8U, 1);
NearestNeighbor(gry, dst);
cvSaveImage("test_nn.jpg", dst);
AreaAveraging(gry, dst);
cvSaveImage("test_aa.jpg", dst);
Lanczos3(gry, dst);
cvSaveImage("test_l3.jpg", dst);
cvReleaseImage(&src);
cvReleaseImage(&dst);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment