📄 imutil.cpp
字号:
// $image\imutil.cpp 1.5 milbo$ image utilities// Warning: this is raw research code -- expect it to be quite messy.// milbo durban dec05#include <windows.h>#include <io.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <time.h>#include <signal.h>#include <float.h>#include <math.h>#include <new.h>#include <direct.h>#include <sys/stat.h>#include <fstream.h>#include <iostream.h>#include "mcommon.hpp"#include "mfile.hpp"#include "image.hpp"#include "imutil.hpp"#include "rgbimutil.hpp"#include "imfile.hpp"#include "jpegutil.hpp"//-----------------------------------------------------------------------------// What do we do with the empty space where we shifted the image? Do this:// fExtend=false: use black (this is the default)// fExtend=true: use the closest edge pixel, thus effectively extending // the edge of of the shifted imagevoid MoveImage (Image &Img, // io int nxShift, int nyShift, bool fVerbose, bool fExtend) // in{int width = Img.width;int height = Img.height;if (fVerbose) { if (nxShift) lprintf("xShift %d ", nxShift); if (nyShift) lprintf("Shift %d ", nyShift); }if (abs(nxShift) >= width) Err("xShift %d is bigger than width %d", nxShift, width);if (abs(nyShift) >= height) Err("yShift %d is bigger than height %d", nyShift, height);nyShift = -nyShift;Image OutImg(width, height, true); // fills image with blackfor (int ix = 0; ix < width; ix++) { int ixOld = ix - nxShift; for (int iy = 0; iy < height; iy++) { int iyOld = iy - nyShift; if (ixOld < 0) { if (fExtend) ixOld = 0; else continue; } else if (ixOld >= width) { if (fExtend) ixOld = width-1; else continue; } if (iyOld < 0) { if (fExtend) iyOld = 0; else continue; } else if (iyOld >= height) { if (fExtend) iyOld = height-1; else continue; } OutImg(ix, iy) = Img(ixOld, iyOld); } }Img = OutImg;}//-----------------------------------------------------------------------------void CropImage (Image &Img, // io int nTopCrop, int nBottomCrop, int nLeftCrop, int nRightCrop, bool fVerbose) // in{int width = Img.width;int height = Img.height;if (fVerbose) { if (nTopCrop) lprintf("CropTop %d ", nTopCrop); if (nBottomCrop) lprintf("CropBottom %d ", nBottomCrop); if (nLeftCrop) lprintf("CropLeft %d ", nLeftCrop); if (nRightCrop) lprintf("CropRight %d ", nRightCrop); }int nNewWidth = Img.width - nLeftCrop - nRightCrop;int nNewHeight = Img.height - nTopCrop - nBottomCrop;if (nTopCrop < 0 || nBottomCrop < 0 || nLeftCrop < 0 || nRightCrop < 0) Err("you can't specify a crop less than 0");if (nNewWidth <= 0) Err("specified left or right crop would cause a width less than or equal to zero");if (nNewWidth > width) Err("specified left or right crop would cause a width bigger than current width");if (nNewHeight <= 0) Err("specified top or bottom crop would cause a height less than or equal to zero");if (nNewHeight > height) Err("specified top or bottom crop would cause a height bigger than current height");Image OutImg(nNewWidth, nNewHeight);for (int iy = 0; iy < nNewHeight; iy++) for (int ix = 0; ix < nNewWidth; ix++) OutImg(ix, iy) = Img(ix + nLeftCrop, iy + nTopCrop);Img = OutImg;}//-----------------------------------------------------------------------------// Will flip horizontally, unless fVertical is true in which case it will flip verticallyvoid FlipImage (Image &Img, // io bool fVertical, bool fVerbose) // in{if (fVerbose) lprintf("Flip%s ", (fVertical? "Vertical": "Horizontal"));int width = Img.width;int height = Img.height;Image OutImg(width, height);if (fVertical) { for (int iy = 0; iy < height; iy++) memcpy(OutImg.buf + iy * width, Img.buf + (height - 1 - iy) * width, width); }else for (int iy = 0; iy < height; iy++) { int Width1 = iy * width; int ix1 = width; for (int ix = 0; ix < width; ix++) OutImg(ix + Width1) = Img(--ix1 + Width1); }Img = OutImg;}//-----------------------------------------------------------------------------// Helper function for ScaleImage. Actually a macro, for speed.static int ig_Pos, ig_Pos1; double g_Frac;#define _InterpolatePixel(pIn, ix, Scale, Max) \{ \ig_Pos = (int)(ix * Scale); \ig_Pos1 = ig_Pos + 1; \if (ig_Pos1 >= Max) \ ig_Pos1 = Max-1; \g_Frac = (ix * Scale) - ig_Pos; \g_Frac = (int)((1.0 - g_Frac) * pIn[ig_Pos] + g_Frac * pIn[ig_Pos1] + 0.5); \}//-----------------------------------------------------------------------------// Scale using two steps of linear interpolation: first in the X direction, // then in the Y direction//// If fBilinear is false we use the nearest pixel (usually a sharper image)//// TODO Is the following a bug? If size is reduced by more than 2, this ignores some // pixels in the input image, even when fBilinear is true -- because we look// a max of 2 pixels when doing bilinear interpretation. // Use ReduceRgbImage if this matters to you.//// I lifted the original version of this from Henry Rowley img.cc:ReduceSize()void ScaleImage (Image &Img, // io const int nNewWidth, const int nNewHeight, const bool fVerbose, const bool fBilinear) // in{int ix, iy;const int width = Img.width;const int height = Img.height;const double scaleX = (double)width /nNewWidth;const double scaleY = (double)height/nNewHeight;if (fVerbose) { if (scaleX > 1) lprintf("ScaleDown %.2g ", 1/scaleX); else if (scaleX < 1) lprintf("ScaleUp %.2g ", 1/scaleX); else lprintf("Scale %.2g ", 1/scaleX); }if (width != nNewWidth || height != nNewHeight) { if (fBilinear) { // scale horizontally Image Out1(nNewWidth, height); byte *pIn = Img.buf; for (iy = 0; iy < height; iy++) { for (ix = 0; ix < nNewWidth; ix++) { _InterpolatePixel(pIn, ix, scaleX, width); Out1(iy + ix * height) = (byte)g_Frac; } pIn += width; } // scale vertically Img.dim(nNewWidth, nNewHeight); byte * const pOut = Img.buf; pIn = Out1.buf; for (iy = 0; iy < nNewWidth; iy++) { for (ix = 0; ix < nNewHeight; ix++) { _InterpolatePixel(pIn, ix, scaleY, height); pOut[iy + ix * nNewWidth] = (byte)g_Frac; } pIn += height; } } else // nearest pixel { Image OutImg(nNewWidth, nNewHeight); for (iy = 0; iy < nNewHeight; iy++) { int iy1 = (iy * height) / nNewHeight; for (ix = 0; ix < nNewWidth; ix++) OutImg(ix, iy) = Img((ix * width) / nNewWidth, iy1); } Img = OutImg; } }}//-----------------------------------------------------------------------------void ExtendImage (Image &Img, // io int nLeft, int nRight, int nTop, int nBottom, bool fVerbose) // in{if (fVerbose) { if (nTop) lprintf("AddTop %d ", nTop); if (nBottom) lprintf("AddBottom %d ", nBottom); if (nLeft) lprintf("AddLeft %d ", nLeft); if (nRight) lprintf("AddRight %d ", nRight); }if (nTop < 0 || nBottom < 0 || nLeft < 0 || nRight < 0) Err("you can't extend an image by less than 0");if (nTop != 0 || nBottom != 0 || nLeft != 0 || nRight != 0) { int width = Img.width; int height = Img.height; Image OutImg(width + nLeft + nRight, height + nTop + nBottom, true); // init to 0 for (int ix = 0; ix < width; ix++) for (int iy = 0; iy < height; iy++) OutImg(ix + nLeft, iy + nBottom) = Img(ix, iy); Img = OutImg; }}//-----------------------------------------------------------------------------// If Scale is integral, this averages all pixels in the source area to make// a pixel in the reduced image.// If Scale is non-integral, it uses bilinear interpolation.void ReduceImage (Image &Img, // io double Scale, int ReduceMethod, bool fVerbose) // in{if (fVerbose) lprintf("Reduce %g ", Scale);if (!fEqual(Scale, 1, 1e-3)) // only reduce if we have to { int iScale, ix, iy; int nNewWidth = int(Img.width / Scale), nNewHeight = int(Img.height / Scale); if (nNewWidth < 10 || nNewHeight < 10) // 10 is rather arbitrary SysErr("ReduceImageAssign: image too small, nNewWidth %d nNewHeight %d", nNewWidth, nNewHeight); switch (ReduceMethod) { case IM_NEAREST_PIXEL: ScaleImage(Img, nNewWidth, nNewHeight, fVerbose, IM_NEAREST_PIXEL); break; case IM_BILINEAR: ScaleImage(Img, nNewWidth, nNewHeight, fVerbose, IM_BILINEAR); break; case IM_AVERAGE_ALL: { ASSERT(fEqual(floor(Scale), Scale, 1e-3)); // scale is an integer? iScale = (int)Scale; // for efficiency do calculations using ints not doubles Image OutImg(nNewWidth, nNewHeight); for (iy = 0; iy < nNewHeight; iy++) for (ix = 0; ix < nNewWidth; ix++) { int Pixel = 0; for (int j = 0; j < iScale; j++) for (int i = 0; i < iScale; i++) Pixel += Img((ix * iScale) + i, iy * iScale + j); OutImg(ix, iy) = byte(Pixel / (iScale * iScale)); } Img = OutImg; // this does a memcpy break; } default: SysErr("CONF_ReduceMethod"); break; } }}//-----------------------------------------------------------------------------// Like ReduceImage but output image is same as input image -- this// is faster because we don't need to copy memory.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -