예제 #1
0
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;
}