IntensityMap GaussianBlur::calculate(IntensityMap &input, double radius, bool tileable) { IntensityMap result = IntensityMap(input.getWidth(), input.getHeight()); gaussBlur(input, result, radius, tileable); return result; }
//displays single color channels of the image (handled by an intensitymap) void MainWindow::displayChannelIntensity() { if(input.isNull()) return; IntensityMap temp; if(ui->radioButton_displayRed->isChecked()) temp = IntensityMap(input, IntensityMap::AVERAGE, true, false, false, false); else if(ui->radioButton_displayGreen->isChecked()) temp = IntensityMap(input, IntensityMap::AVERAGE, false, true, false, false); else if(ui->radioButton_displayBlue->isChecked()) temp = IntensityMap(input, IntensityMap::AVERAGE, false, false, true, false); else temp = IntensityMap(input, IntensityMap::AVERAGE, false, false, false, true); this->channelIntensity = temp.convertToQImage(); preview(0); }
QImage NormalmapGenerator::calculateNormalmap(const QImage& input, Kernel kernel, double strength, bool invert, bool tileable, bool keepLargeDetail, int largeDetailScale, double largeDetailHeight) { this->tileable = tileable; this->intensity = IntensityMap(input, mode, redMultiplier, greenMultiplier, blueMultiplier, alphaMultiplier); if(!invert) { // The default "non-inverted" normalmap looks wrong in renderers, // so I use inversion by default intensity.invert(); } QImage result(input.width(), input.height(), QImage::Format_ARGB32); // optimization double strengthInv = 1.0 / strength; #pragma omp parallel for // OpenMP //code from http://stackoverflow.com/a/2368794 for(int y = 0; y < input.height(); y++) { QRgb *scanline = (QRgb*) result.scanLine(y); for(int x = 0; x < input.width(); x++) { const double topLeft = intensity.at(handleEdges(x - 1, input.width()), handleEdges(y - 1, input.height())); const double top = intensity.at(handleEdges(x - 1, input.width()), handleEdges(y, input.height())); const double topRight = intensity.at(handleEdges(x - 1, input.width()), handleEdges(y + 1, input.height())); const double right = intensity.at(handleEdges(x, input.width()), handleEdges(y + 1, input.height())); const double bottomRight = intensity.at(handleEdges(x + 1, input.width()), handleEdges(y + 1, input.height())); const double bottom = intensity.at(handleEdges(x + 1, input.width()), handleEdges(y, input.height())); const double bottomLeft = intensity.at(handleEdges(x + 1, input.width()), handleEdges(y - 1, input.height())); const double left = intensity.at(handleEdges(x, input.width()), handleEdges(y - 1, input.height())); const double convolution_kernel[3][3] = {{topLeft, top, topRight}, {left, 0.0, right}, {bottomLeft, bottom, bottomRight}}; QVector3D normal(0, 0, 0); if(kernel == SOBEL) normal = sobel(convolution_kernel, strengthInv); else if(kernel == PREWITT) normal = prewitt(convolution_kernel, strengthInv); scanline[x] = qRgb(mapComponent(normal.x()), mapComponent(normal.y()), mapComponent(normal.z())); } } if(keepLargeDetail) { //generate a second normalmap from a downscaled input image, then mix both normalmaps int largeDetailMapWidth = (int) (((double)input.width() / 100.0) * largeDetailScale); int largeDetailMapHeight = (int) (((double)input.height() / 100.0) * largeDetailScale); //create downscaled version of input QImage inputScaled = input.scaled(largeDetailMapWidth, largeDetailMapHeight, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); //compute downscaled normalmap QImage largeDetailMap = calculateNormalmap(inputScaled, kernel, largeDetailHeight, invert, tileable, false, 0, 0.0); //scale map up largeDetailMap = largeDetailMap.scaled(input.width(), input.height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); #pragma omp parallel for // OpenMP //mix the normalmaps for(int y = 0; y < input.height(); y++) { QRgb *scanlineResult = (QRgb*) result.scanLine(y); QRgb *scanlineLargeDetail = (QRgb*) largeDetailMap.scanLine(y); for(int x = 0; x < input.width(); x++) { const QRgb colorResult = scanlineResult[x]; const QRgb colorLargeDetail = scanlineLargeDetail[x]; const int r = blendSoftLight(qRed(colorResult), qRed(colorLargeDetail)); const int g = blendSoftLight(qGreen(colorResult), qGreen(colorLargeDetail)); const int b = blendSoftLight(qBlue(colorResult), qBlue(colorLargeDetail)); scanlineResult[x] = qRgb(r, g, b); } } } return result; }