inline Pixel * pixelAt(Image *image, unsigned int x, unsigned int y) { if(x > image->width) { return pixelAt(image, x - 1, y); } if(y > image->height) { return pixelAt(image, x, y - 1); } return &(image->canvas[(y * image->width) + x]); }
/** * @param x * @param y * @return invalid color if x or y is outside image boundaries */ QColor Layer::colorAt(int x, int y) const { if(x<0 || y<0 || x>=_width || y>=_height) return QColor(); return QColor::fromRgb(pixelAt(x, y)); }
void Image::applyMaskMixForMaskInvert(const RectI& roi, const Image* maskImg, const Image* originalImg, float mix) { PIX* dst_pixels = (PIX*)pixelAt(roi.x1, roi.y1); unsigned int dstRowElements = _bounds.width() * getComponentsCount(); for ( int y = roi.y1; y < roi.y2; ++y, dst_pixels += (dstRowElements - (roi.x2 - roi.x1) * dstNComps) ) { // 1 row stride minus what was done at previous iteration for (int x = roi.x1; x < roi.x2; ++x, dst_pixels += dstNComps) { const PIX* src_pixels = originalImg ? (const PIX*)originalImg->pixelAt(x, y) : 0; float maskScale = 1.f; if (!masked) { // just mix float alpha = mix; if (src_pixels) { for (int c = 0; c < dstNComps; ++c) { if (c < srcNComps) { float v = float(dst_pixels[c]) * alpha + (1.f - alpha) * float(src_pixels[c]); dst_pixels[c] = clampIfInt<PIX>(v); } } } else { for (int c = 0; c < dstNComps; ++c) { float v = float(dst_pixels[c]) * alpha; dst_pixels[c] = clampIfInt<PIX>(v); } } } else { const PIX* maskPixels = maskImg ? (const PIX*)maskImg->pixelAt(x, y) : 0; // figure the scale factor from that pixel if (maskPixels == 0) { maskScale = maskInvert ? 1.f : 0.f; } else { maskScale = *maskPixels / float(maxValue); if (maskInvert) { maskScale = 1.f - maskScale; } } float alpha = mix * maskScale; if (src_pixels) { for (int c = 0; c < dstNComps; ++c) { if (c < srcNComps) { float v = float(dst_pixels[c]) * alpha + (1.f - alpha) * float(src_pixels[c]); dst_pixels[c] = clampIfInt<PIX>(v); } } } else { for (int c = 0; c < dstNComps; ++c) { float v = float(dst_pixels[c]) * alpha; dst_pixels[c] = clampIfInt<PIX>(v); } } } } } } // Image::applyMaskMixForMaskInvert
pixel3f *Image::createGaussian(float sigma) { pixel3f *gaussian = new pixel3f[_width * _height](); // Precompute constants. float variance = sigma * sigma; float denomiator = 2 * M_PI * variance; // Radius of filter. int r = 2.0f * sigma; float *kernel = createGaussianKernel(r + 1, variance); // Seperable x component of Gaussian filter. for (int x = 0; x < _width; x++) { for (int y = 0; y < _height; y++) { float sum = 0; for (int i = -r; i <= r; i++) { sum += pixelAt(_pixels, x + i, y)->L * kernel[abs(i)]; } // Do not divide by the regular denominator. pixelAt(_copy, x, y)->L = sum; } } // Seperable y component of Gaussian filter. for (int x = 0; x < _width; x++) { for (int y = 0; y < _height; y++) { float sum = 0; for (int j = -r; j <= r; j++) { sum += pixelAt(_copy, x, y + j)->L * kernel[abs(j)]; } // Divided by the denominator squared only once rather than twice. pixelAt(gaussian, x, y)->L = sum / denomiator; } } // Free temporary data. delete[] kernel; return gaussian; }
std::vector<Eigen::Vector3f> ImageReader::toVector(){ std::vector<Eigen::Vector3f> output; for (int i = 0; i < getImageHeight(); i++) { for (int j = 0; j < getImageWidth(); j++) { QColor pixelColor = QColor(pixelAt(i,j)); Eigen::Vector3f color = Eigen::Vector3f(float(pixelColor.red()), float(pixelColor.green()), float(pixelColor.blue())); output.push_back(color); } } return output; }
void convertToRGB(uint32_t *outPixels) const { for (unsigned int x = 0; x < m_width; ++x) { for (unsigned int y = 0; y < m_height; ++y) { PixelSample &sample = pixelAt(x, y); if (sample.filterAccum != 0) { outPixels[x + y*m_width] = mapRGB(sample.accum / sample.filterAccum); } else { outPixels[x + y*m_width] = mapRGB(Vec()); } } } }
void addSample(float x, float y, Vec const &value) { int x1 = ceil2Int(x - m_filterWidth); int x2 = floor2Int(x + m_filterWidth); int y1 = ceil2Int(y - m_filterHeight); int y2 = ceil2Int(y + m_filterWidth); x1 = std::max(0, x1); x2 = std::min(x2, m_width); y1 = std::max(0, y1); y2 = std::min(y2, m_height); // update all pixels affected by the sample for (int ix = x1; ix < x2; ++ix) { for (int iy = y1; iy < y2; ++iy) { float filterVal = evalFilter( fabsf(static_cast<float>(ix) - x), fabsf(static_cast<float>(iy) - y)); pixelAt(ix, iy).accum += filterVal * value; pixelAt(ix, iy).filterAccum += filterVal; } } }
/** * @param x * @param y * @return invalid color if x or y is outside image boundaries */ QColor Layer::colorAt(int x, int y, int dia) const { if(x<0 || y<0 || x>=_width || y>=_height) return QColor(); if(dia<=1) { quint32 c = pixelAt(x, y); if(qAlpha(c)==0) return QColor(); return QColor::fromRgb(c); } else { Brush b(dia, 0.9); BrushStamp bs = makeGimpStyleBrushStamp(b, Point(x, y, 1)); return getDabColor(bs); } }
void ImageReader::findMinAndMax() { int min = 10000000000; int max = -1; for (int i = 0; i < getImageHeight(); i++) { for (int j = 0; j < getImageWidth(); j++) { if (QColor(pixelAt(i,j)).red() > 150) { if (j > max) { max = j; } if (j < min) { min = j; } } } } assert(max > min); m_xMax = max; m_xMin = min; }
void Image::copyUnProcessedChannelsForPremult(const std::bitset<4> processChannels, const RectI& roi, const ImagePtr& originalImage) { Q_UNUSED(processChannels); // silence warnings in release version assert( ( (doR == !processChannels[0]) || !(dstNComps >= 2) ) && ( (doG == !processChannels[1]) || !(dstNComps >= 2) ) && ( (doB == !processChannels[2]) || !(dstNComps >= 3) ) && ( (doA == !processChannels[3]) || !(dstNComps == 1 || dstNComps == 4) ) ); ReadAccess acc( originalImage.get() ); int dstRowElements = dstNComps * _bounds.width(); PIX* dst_pixels = (PIX*)pixelAt(roi.x1, roi.y1); assert(dst_pixels); assert(srcNComps == 1 || srcNComps == 4 || !originalPremult); // only A or RGBA can be premult assert(dstNComps == 1 || dstNComps == 4 || !premult); // only A or RGBA can be premult for ( int y = roi.y1; y < roi.y2; ++y, dst_pixels += (dstRowElements - (roi.x2 - roi.x1) * dstNComps) ) { for (int x = roi.x1; x < roi.x2; ++x, dst_pixels += dstNComps) { const PIX* src_pixels = originalImage ? (const PIX*)acc.pixelAt(x, y) : 0; PIX srcA = src_pixels ? maxValue : 0; /* be opaque for anything that doesn't contain alpha */ if ( ( (srcNComps == 1) || (srcNComps == 4) ) && src_pixels ) { # ifdef DEBUG assert(src_pixels[srcNComps - 1] == src_pixels[srcNComps - 1]); // check for NaN # endif srcA = src_pixels[srcNComps - 1]; } # ifdef NATRON_COPY_CHANNELS_UNPREMULT // Repremult R G and B if output is premult and alpha was modified. // We do not consider it a good thing, since the user explicitely deselected the channels, and expects // to get the values from input instead. # define DOCHANNEL(c) \ if (srcNComps == 1 || !src_pixels || c >= srcNComps) { \ dst_pixels[c] = 0; \ } \ else if (originalPremult) { \ if (srcA == 0) { \ dst_pixels[c] = src_pixels[c]; /* don't try to unpremult, just copy */ \ } \ else if (premult) { \ if (doA) { \ dst_pixels[c] = src_pixels[c]; /* dst will have same alpha as src, just copy src */ \ } \ else { \ dst_pixels[c] = (src_pixels[c] / (float)srcA) * dstAorig; /* dst keeps its alpha, unpremult src and repremult */ \ } \ } \ else { \ dst_pixels[c] = (src_pixels[c] / (float)srcA) * maxValue; /* dst is not premultiplied, unpremult src */ \ } \ } \ else { \ if (premult) { \ if (doA) { \ dst_pixels[c] = (src_pixels[c] / (float)maxValue) * srcA; /* dst will have same alpha as src, just premult src with its alpha */ \ } \ else { \ dst_pixels[c] = (src_pixels[c] / (float)maxValue) * dstAorig; /* dst keeps its alpha, premult src with dst's alpha */ \ } \ } \ else { \ dst_pixels[c] = src_pixels[c]; /* neither src nor dst is not premultiplied */ \ } \ } PIX dstAorig = maxValue; # else // !NATRON_COPY_CHANNELS_UNPREMULT // Just copy the channels, after all if the user unchecked a channel, // we do not want to change the values behind his back. // Rather we display a warning in the GUI. # define DOCHANNEL(c) dst_pixels[c] = (!src_pixels || c >= srcNComps) ? 0 : src_pixels[c]; # endif // !NATRON_COPY_CHANNELS_UNPREMULT if ( (dstNComps == 1) || (dstNComps == 4) ) { # ifdef DEBUG assert(dst_pixels[dstNComps - 1] == dst_pixels[dstNComps - 1]); // check for NaN # endif # ifdef NATRON_COPY_CHANNELS_UNPREMULT dstAorig = dst_pixels[dstNComps - 1]; # endif // NATRON_COPY_CHANNELS_UNPREMULT } if (doR) { # ifdef DEBUG assert(!src_pixels || src_pixels[0] == src_pixels[0]); // check for NaN assert(dst_pixels[0] == dst_pixels[0]); // check for NaN # endif DOCHANNEL(0); # ifdef DEBUG assert(dst_pixels[0] == dst_pixels[0]); // check for NaN # endif } if (doG) { # ifdef DEBUG assert(!src_pixels || src_pixels[1] == src_pixels[1]); // check for NaN assert(dst_pixels[1] == dst_pixels[1]); // check for NaN # endif DOCHANNEL(1); # ifdef DEBUG assert(dst_pixels[1] == dst_pixels[1]); // check for NaN # endif } if (doB) { # ifdef DEBUG assert(!src_pixels || src_pixels[2] == src_pixels[2]); // check for NaN assert(dst_pixels[2] == dst_pixels[2]); // check for NaN # endif DOCHANNEL(2); # ifdef DEBUG assert(dst_pixels[2] == dst_pixels[2]); // check for NaN # endif } if (doA) { # ifdef NATRON_COPY_CHANNELS_UNPREMULT if (premult) { if (dstAorig != 0) { // unpremult, then premult if ( (dstNComps >= 2) && !doR ) { dst_pixels[0] = (dst_pixels[0] / (float)dstAorig) * srcA; # ifdef DEBUG assert(dst_pixels[0] == dst_pixels[0]); // check for NaN # endif } if ( (dstNComps >= 2) && !doG ) { dst_pixels[1] = (dst_pixels[1] / (float)dstAorig) * srcA; # ifdef DEBUG assert(dst_pixels[1] == dst_pixels[1]); // check for NaN # endif } if ( (dstNComps >= 2) && !doB ) { dst_pixels[2] = (dst_pixels[2] / (float)dstAorig) * srcA; # ifdef DEBUG assert(dst_pixels[2] == dst_pixels[2]); // check for NaN # endif } } } # endif // NATRON_COPY_CHANNELS_UNPREMULT if ( (dstNComps == 1) || (dstNComps == 4) ) { dst_pixels[dstNComps - 1] = srcA; # ifdef DEBUG assert(dst_pixels[dstNComps - 1] == dst_pixels[dstNComps - 1]); // check for NaN # endif } } } } } // Image::copyUnProcessedChannelsForPremult
void Image::copyUnProcessedChannelsForPremult(const bool premult, const bool originalPremult, const std::bitset<4> processChannels, const RectI& roi, const ImagePtr& originalImage) { ReadAccess acc( originalImage.get() ); int dstRowElements = dstNComps * _bounds.width(); PIX* dst_pixels = (PIX*)pixelAt(roi.x1, roi.y1); assert(dst_pixels); const bool doR = !processChannels[0] && (dstNComps >= 2); const bool doG = !processChannels[1] && (dstNComps >= 2); const bool doB = !processChannels[2] && (dstNComps >= 3); const bool doA = !processChannels[3] && (dstNComps == 1 || dstNComps == 4); assert(srcNComps == 4 || !originalPremult); // only RGBA can be premult assert(dstNComps == 4 || !premult); // only RGBA can be premult Q_UNUSED(premult); Q_UNUSED(originalPremult); for ( int y = roi.y1; y < roi.y2; ++y, dst_pixels += (dstRowElements - (roi.x2 - roi.x1) * dstNComps) ) { for (int x = roi.x1; x < roi.x2; ++x, dst_pixels += dstNComps) { const PIX* src_pixels = originalImage ? (const PIX*)acc.pixelAt(x, y) : 0; PIX srcA = src_pixels ? maxValue : 0; /* be opaque for anything that doesn't contain alpha */ if ( ( (srcNComps == 1) || (srcNComps == 4) ) && src_pixels ) { # ifdef DEBUG assert(src_pixels[srcNComps - 1] == src_pixels[srcNComps - 1]); // check for NaN # endif srcA = src_pixels[srcNComps - 1]; } # ifdef NATRON_COPY_CHANNELS_UNPREMULT PIX dstAorig = maxValue; # endif if ( (dstNComps == 1) || (dstNComps == 4) ) { # ifdef DEBUG assert(dst_pixels[dstNComps - 1] == dst_pixels[dstNComps - 1]); // check for NaN # endif # ifdef NATRON_COPY_CHANNELS_UNPREMULT dstAorig = dst_pixels[dstNComps - 1]; # endif } if (doR) { # ifdef DEBUG assert(!src_pixels || src_pixels[0] == src_pixels[0]); // check for NaN assert(dst_pixels[0] == dst_pixels[0]); // check for NaN # endif DOCHANNEL(0); # ifdef DEBUG assert(dst_pixels[0] == dst_pixels[0]); // check for NaN # endif } if (doG) { # ifdef DEBUG assert(!src_pixels || src_pixels[1] == src_pixels[1]); // check for NaN assert(dst_pixels[1] == dst_pixels[1]); // check for NaN # endif DOCHANNEL(1); # ifdef DEBUG assert(dst_pixels[1] == dst_pixels[1]); // check for NaN # endif } if (doB) { # ifdef DEBUG assert(!src_pixels || src_pixels[2] == src_pixels[2]); // check for NaN assert(dst_pixels[2] == dst_pixels[2]); // check for NaN # endif DOCHANNEL(2); # ifdef DEBUG assert(dst_pixels[2] == dst_pixels[2]); // check for NaN # endif } if (doA) { # ifdef NATRON_COPY_CHANNELS_UNPREMULT if (premult) { if (dstAorig != 0) { // unpremult, then premult if ( (dstNComps >= 2) && !doR ) { dst_pixels[0] = (dst_pixels[0] / (float)dstAorig) * srcA; # ifdef DEBUG assert(dst_pixels[0] == dst_pixels[0]); // check for NaN # endif } if ( (dstNComps >= 2) && !doG ) { dst_pixels[1] = (dst_pixels[1] / (float)dstAorig) * srcA; # ifdef DEBUG assert(dst_pixels[1] == dst_pixels[1]); // check for NaN # endif } if ( (dstNComps >= 2) && !doB ) { dst_pixels[2] = (dst_pixels[2] / (float)dstAorig) * srcA; # ifdef DEBUG assert(dst_pixels[2] == dst_pixels[2]); // check for NaN # endif } } } # endif // NATRON_COPY_CHANNELS_UNPREMULT // coverity[dead_error_line] dst_pixels[dstNComps - 1] = srcA; # ifdef DEBUG assert(dst_pixels[dstNComps - 1] == dst_pixels[dstNComps - 1]); // check for NaN # endif } } } } // Image::copyUnProcessedChannelsForPremult
void gdResample(Image *dst, Image *src, int dstX, int dstY, int srcX, int srcY, int dstW, int dstH, int srcW, int srcH) { int x, y; double sy1, sy2, sx1, sx2; for (y = dstY; (y < dstY + dstH); y++) { sy1 = ((double) y - (double) dstY) * (double) srcH / (double) dstH; sy2 = ((double) (y + 1) - (double) dstY) * (double) srcH / (double) dstH; for (x = dstX; (x < dstX + dstW); x++) { double sx, sy; double spixels = 0; double red = 0.0, green = 0.0, blue = 0.0, alpha = 0.0; sx1 = ((double) x - (double) dstX) * (double) srcW / dstW; sx2 = ((double) (x + 1) - (double) dstX) * (double) srcW / dstW; sy = sy1; do { double yportion; if(floor (sy) == floor (sy1)) { yportion = 1.0 - (sy - floor (sy)); if(yportion > sy2 - sy1) { yportion = sy2 - sy1; } sy = floor (sy); } else if(sy == floor (sy2)) { yportion = sy2 - floor (sy2); } else { yportion = 1.0; } sx = sx1; do { double xportion; double pcontribution; Pixel p; if(floor (sx) == floor (sx1)) { xportion = 1.0 - (sx - floor (sx)); if(xportion > sx2 - sx1) { xportion = sx2 - sx1; } sx = floor (sx); } else if (sx == floor (sx2)) { xportion = sx2 - floor (sx2); } else { xportion = 1.0; } pcontribution = xportion * yportion; p = *pixelAt(src, floor(sx + srcX), floor(sy + srcY)); red += p.red * pcontribution; green += p.green * pcontribution; blue += p.blue * pcontribution; spixels += xportion * yportion; sx += 1.0; } while (sx < sx2); sy += 1.0; } while (sy < sy2); if(spixels != 0.0) { red /= spixels; green /= spixels; blue /= spixels; alpha /= spixels; } if(red > 255.0) red = 255.0; if(green > 255.0) green = 255.0; if(blue > 255.0) blue = 255.0; Pixel *p = pixelAt(dst, x, y); p->red = red; p->green = green; p->blue = blue; } } }
void Image::bilateral() { // Gaussian kernel used to model geometric similarity. float *kernel = createGaussianKernel(RADIUS + 1, VARIANCE); for (int x = 0; x < _width; x++) { for (int y = 0; y < _height; y++) { pixel3f *center = pixelAt(_pixels, x, y); float numerator = 0; float denominator = 0; for (int i = -RADIUS; i <= RADIUS; i++) { pixel3f *neighbor = pixelAt(_pixels, x + i, y); // Compute euclidean distance between Lab colors to determine photometric similarity. float dL = center->L - neighbor->L; float da = center->a - center->a; float db = center->b - center->b; float distance = dL * dL + da * da + db * db; float photometric = expf(distance / PHOTOMETRIC); float similarity = photometric * kernel[abs(i)]; // Denominator serves to normalize values. denominator += similarity; numerator += similarity * neighbor->L; } // Copy a and b data over as well to use for the y-filter pass. pixel3f *target = pixelAt(_copy, x, y); target->L = numerator / denominator; target->a = center->a; target->b = center->b; } } for (int x = 0; x < _width; x++) { for (int y = 0; y < _height; y++) { pixel3f *center = pixelAt(_copy, x, y); float numerator = 0; float denominator = 0; for (int j = -RADIUS; j <= RADIUS; j++) { pixel3f *neighbor = pixelAt(_copy, x, y + j); float dL = center->L - neighbor->L; float da = center->a - center->a; float db = center->b - center->b; float distance = dL * dL + da * da + db * db; float photometric = expf(distance / PHOTOMETRIC); float similarity = photometric * kernel[abs(j)]; denominator += similarity; numerator += similarity * neighbor->L; } pixelAt(_pixels, x, y)->L = numerator / denominator; } } delete[] kernel; }
void getScreenBytes(unsigned char* bytes) { int c64bytes = getScreenBytesSize(); memset(bytes, 0, c64bytes); int width = getWidth(); int height = getHeight(); for (int h = 0; h < height; h++) { for (int w = 0; w < width; w++) { //printf("src %d = %d\n", h*width+w, src[h*width+w]); int xblock = w / xBlockSize; int yblock = h / yBlockSize; Pixel* p = pixelAt(w, h); // determine bitmask based on the palette index // bgcolor = 0x00 // fgcolor = 0x03 // block color 0 = 0x01 // block color 1 = 0x02 unsigned char mask = 0; if (p->palette_index == bgcolor) { mask = 0x00; } else if (p->palette_index == fgcolor) { mask = 0x03; } else if (p->palette_index == getBlockColor(xblock, yblock, 0)) { mask = 0x01; } else if (p->palette_index == getBlockColor(xblock, yblock, 1)) { mask = 0x02; } else { printf("this should not happen."); } // set bits in bitmap byte int screen_width = w*2; int row = h / 8; int c = screen_width / 8; int line = h & 7; int bit = 7 - (screen_width & 7); int byte = row*320 + c*8 + line; unsigned char b = bytes[byte]; // raise 2 bits (fg color) bit--; if (bit < 0) bit = 0; unsigned char shifted_mask = mask << bit; b = b | shifted_mask; bytes[byte] = b; } } }