openframeworks / openframeworks/openFrameworks
ofPixels - artifacts / crashes with .resize()
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 10.4k
- Forks
- 2.6k
- Avg merge
- 1d 21h
- Merged PRs (30d)
- 9
Description
Since ofPixels.cpp has not been updated for over a year in the master branch, i therefore assume the following issue has not been fixed. i am using of 0.10.1 with win10 vs2017.
I am resizing images/pixels with the following function.
That leads to issues:
- OF_INTERPOLATE_NEAREST_NEIGHBOR crashes on large sizes
- OF_INTERPOLATE_BILINEAR: produces grey only pixels. well yes, "not implemented yet" in ofPixels
- OF_INTERPOLATE_BICUBIC produces some singular green pixel/blue artifacts
calling the same function using image.resize() produces best results
question: i assume that i may use pixelsRes = _pixels; to create a full twin copy, right?
if yes, then there is the described issue in the pixel resizeTo() function.
CODE:
#include "ofApp.h"
/*
this function aims to either
- crop the image to the largest possible dimensions respecting _aspect
then scales the longest side to _longestSideLengthPx
- stretch it respecting _aspect
then scales the longest side to _longestSideLengthPx
*/
static void resize(
ofPixels &_pixels,
const float &_longestSideLengthPx,
const ofVec2f &_aspect,
const bool &_bStretch, // otherwise crop
const ofInterpolationMethod &_interp // OF_INTERPOLATE_NEAREST_NEIGHBOR OF_INTERPOLATE_BILINEAR
) {
ofScaleMode _scaleMode = _bStretch ? OF_SCALEMODE_FILL : OF_SCALEMODE_FIT;
ofRectangle rectPixels(0, 0, _pixels.getWidth(), _pixels.getHeight());
ofRectangle rectAspect(0, 0, _aspect.x, _aspect.y);
rectAspect.scaleTo(rectPixels, _scaleMode);
ofPixels pixelsRes;
if (_scaleMode == OF_SCALEMODE_FIT) { // crop
_pixels.cropTo(pixelsRes, rectAspect.x, rectAspect.y, rectAspect.width, rectAspect.height);
}
else { // stretch
pixelsRes = _pixels;
// Q: is this a complete copy with new identical pixels?
// looks like it does copy all params plus the pixels:
//template<typename PixelType>
//void ofPixels_<PixelType>::copyFrom(const ofPixels_<PixelType> & mom) {
// if (mom.isAllocated()) {
// allocate(mom.getWidth(), mom.getHeight(), mom.getPixelFormat());
// memcpy(pixels, mom.getData(), getTotalBytes());
// }
//}
}
ofRectangle rectSize;
if (rectAspect.width > rectAspect.height) {
assert(rectAspect.width > 0);
rectSize.set(0, 0, _longestSideLengthPx, _longestSideLengthPx / rectAspect.width * rectAspect.height);
}
else {
assert(rectAspect.height > 0);
rectSize.set(0, 0, _longestSideLengthPx / rectAspect.height * rectAspect.width, _longestSideLengthPx);
}
ofLogNotice(__FUNCTION__) << "scaling _pixels: rectSize: " << rectSize;
ofLogNotice(__FUNCTION__) << "_aspect : " << _aspect;
ofLogNotice(__FUNCTION__) << "_scaleMode: " << _scaleMode;
ofLogNotice(__FUNCTION__) << "_interp : " << _interp;
ofLogNotice(__FUNCTION__) << "rectPixels: " << rectPixels;
ofLogNotice(__FUNCTION__) << "rectAspect: " << rectAspect;
#if 1
// ISSUE is right here
// OF_INTERPOLATE_NEAREST_NEIGHBOR crashes on large sizes
// OF_INTERPOLATE_BILINEAR : produces grey only pixels.well yes, "not implemented yet" in ofPixels
// OF_INTERPOLATE_BICUBIC produces some singular green pixel / blue artifacts
// calling above function via image.resize() produces best results
bool b = pixelsRes.resize(rectSize.width, rectSize.height, _interp); // THIS SEEMS BUGGY in 0.10.1
assert(b);
_pixels = pixelsRes;
#else
// all ok - done with freeimage functions
ofImage image(pixelsRes);
image.resize(rectSize.width, rectSize.height); // freeimage
_pixels.setFromPixels(
image.getPixels().getData(),
image.getWidth(),
image.getHeight(),
image.getImageType()
);
#endif
}
//--------------------------------------------------------------
void ofApp::setup() {
ofSetLogLevel(OF_LOG_NOTICE);
ofImage image;
int longestSide = 15000; // somehow works with small size like 1000, crashes on large sizes
ofInterpolationMethod interp;
for (int i = 1; i <= 3; i++)
{
ofLogNotice(__FUNCTION__) << i;
switch (i)
{
case 1: interp = OF_INTERPOLATE_NEAREST_NEIGHBOR; break;
case 2: interp = OF_INTERPOLATE_BILINEAR; break;
case 3: interp = OF_INTERPOLATE_BICUBIC; break;
default:
std::exit(1);
break;
}
bool b = image.load("face.jpg");
assert(b);
bool bStretch = true;
image.load("face.jpg");
resize(image.getPixels(), longestSide, ofVec2f(16, 9), bStretch, interp);
// how does the image know that the pixels are scaled now?
image.setFromPixels(image.getPixels()); // ???
image.save("face_169_stretch_" + ofToString(i) + ".jpg");
image.load("face.jpg");
resize(image.getPixels(), longestSide, ofVec2f(9, 16), bStretch, interp);
image.setFromPixels(image.getPixels()); // ???
image.save("face_916_stretch_" + ofToString(i) + ".jpg");
bStretch = false;
image.load("face.jpg");
resize(image.getPixels(), longestSide, ofVec2f(16, 9), bStretch, interp);
image.setFromPixels(image.getPixels()); // ???
image.save("face_169_crop_" + ofToString(i) + ".jpg");
image.load("face.jpg");
resize(image.getPixels(), longestSide, ofVec2f(9, 16), bStretch, interp);
image.setFromPixels(image.getPixels()); // ???
image.save("face_916_crop_" + ofToString(i) + ".jpg");
}
}
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the ofPixels.cpp resize implementation and reproduce the supplied example using face.jpg, a longest side of 15000, and each interpolation method. Compare pixelsRes.resize() with image.resize() for the reported crash, grey output, and colored artifacts. Done means the resize path handles the supplied cases without crashing and produces correct output for the supported interpolation methods.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- computer-graphics
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100