照片/图像到草图算法

2022-09-05 00:04:04

有没有人有一个想法,链接,库,源代码,...如何将照片和图像(位图)转换为粗略的图片?我找不到任何关于如何做到这一点的好来源。

我发现这个链接 如何以编程方式卡通化图像?关于如何以编程方式卡通化图像,但我更喜欢让它成为图像到素描。

我想制作一个Android应用程序,可以编程方式将JPEG照片“转换”为粗略的图像。


答案 1

好吧,所以我用不同的技术找到了自己的答案,就像马克告诉我的那样。我使用以下伪代码:

*s = Read-File-Into-Image("/path/to/image")
*g = Convert-To-Gray-Scale(s)
*i = Invert-Colors(g)
*b = Apply-Gaussian-Blur(i)
*result = Color-Dodge-Blend-Merge(b,g)

前四种方法很容易在互联网上找到,但是在最后一个方法上,我找不到很多信息,甚至没有源代码。所以我搜索了PS是如何做到的,并在c ++中找到了以下公式:

((uint8)((B == 255) ? B:min(255, ((A << 8 ) / (255 - B)))))

然后我用下面的代码将其转换为Java:

private int colordodge(int in1, int in2) {
    float image = (float)in2;
    float mask = (float)in1;
    return ((int) ((image == 255) ? image:Math.min(255, (((long)mask << 8 ) / (255 - image)))));

}

/**
 * Blends 2 bitmaps to one and adds the color dodge blend mode to it.
 */
public Bitmap ColorDodgeBlend(Bitmap source, Bitmap layer) {
    Bitmap base = source.copy(Config.ARGB_8888, true);
    Bitmap blend = layer.copy(Config.ARGB_8888, false);

    IntBuffer buffBase = IntBuffer.allocate(base.getWidth() * base.getHeight());
    base.copyPixelsToBuffer(buffBase);
    buffBase.rewind();

    IntBuffer buffBlend = IntBuffer.allocate(blend.getWidth() * blend.getHeight());
    blend.copyPixelsToBuffer(buffBlend);
    buffBlend.rewind();

    IntBuffer buffOut = IntBuffer.allocate(base.getWidth() * base.getHeight());
    buffOut.rewind();

    while (buffOut.position() < buffOut.limit()) {
        int filterInt = buffBlend.get();
        int srcInt = buffBase.get();

        int redValueFilter = Color.red(filterInt);
        int greenValueFilter = Color.green(filterInt);
        int blueValueFilter = Color.blue(filterInt);

        int redValueSrc = Color.red(srcInt);
        int greenValueSrc = Color.green(srcInt);
        int blueValueSrc = Color.blue(srcInt);

        int redValueFinal = colordodge(redValueFilter, redValueSrc);
        int greenValueFinal = colordodge(greenValueFilter, greenValueSrc);
        int blueValueFinal = colordodge(blueValueFilter, blueValueSrc);

        int pixel = Color.argb(255, redValueFinal, greenValueFinal, blueValueFinal);

        buffOut.put(pixel);
    }

    buffOut.rewind();

    base.copyPixelsFromBuffer(buffOut);
    blend.recycle();

    return base;
}

如果代码可以改进,请在下面发布新的答案或评论。谢谢!


答案 2

并添加颜色。

*s = Read-File-Into-Image("/path/to/image")
*g = Convert-To-Gray-Scale(s)
*i = Invert-Colors(g)
*b = Apply-Gaussian-Blur(i)
*result = Color-Dodge-Blend-Merge(b,g)   
*s2 = Apply-Gaussian-Blur(s) //I use radius 3
*cartoon = Apply-Color(s2, result)

我很少修改以消除所有颜色。ColorDodgeBlend

public Bitmap ColorDodgeBlend(Bitmap source, Bitmap layer) 
....
//before buffOut.put(pixel);

float[] hsv = new float[3];
        Color.colorToHSV(pixel, hsv);
        hsv[1] = 0.0f;
        float top = VALUE_TOP; //Between 0.0f .. 1.0f I use 0.87f
        if (hsv[2] <= top) {
            hsv[2] = 0.0f;
        } else {
            hsv[2] = 1.0f;
        }
        pixel = Color.HSVToColor(hsv);

应用颜色方法:

//hue, saturarion, value intervals size are for reduce colors on Bitmap
//saturation, value percents are for increment or decrement [0..100..)
public Bitmap getCartoonizedBitmap(Bitmap realBitmap, Bitmap dodgeBlendBitmap, int hueIntervalSize, int saturationIntervalSize, int valueIntervalSize, int saturationPercent, int valuePercent) {
    // Bitmap bitmap = Bitmap.createBitmap(scaledBitmap);
    // //fastblur(scaledBitmap, 4);
    Bitmap base = fastblur(realBitmap, 3).copy(Config.ARGB_8888, true);
    Bitmap dodge = dodgeBlendBitmap.copy(Config.ARGB_8888, false);
    try {
        int realColor;
        int color;
        float top = VALUE_TOP; //Between 0.0f .. 1.0f I use 0.87f
        IntBuffer templatePixels = IntBuffer.allocate(dodge.getWidth()
                * dodge.getHeight());
        IntBuffer scaledPixels = IntBuffer.allocate(base.getWidth()
                * base.getHeight());
        IntBuffer buffOut = IntBuffer.allocate(base.getWidth()
                * base.getHeight());

        base.copyPixelsToBuffer(scaledPixels);
        dodge.copyPixelsToBuffer(templatePixels);

        templatePixels.rewind();
        scaledPixels.rewind();
        buffOut.rewind();

        while (buffOut.position() < buffOut.limit()) {
            color = (templatePixels.get());
            realColor = scaledPixels.get();

            float[] realHSV = new float[3];
            Color.colorToHSV(realColor, realHSV);

            realHSV[0] = getRoundedValue(realHSV[0], hueIntervalSize);

            realHSV[2] = (getRoundedValue(realHSV[2] * 100,
                    valueIntervalSize) / 100) * (valuePercent / 100);
            realHSV[2] = realHSV[2]<1.0?realHSV[2]:1.0f;

            realHSV[1] = realHSV[1] * (saturationPercent / 100);
            realHSV[1] = realHSV[1]<1.0?realHSV[1]:1.0f;

            float[] HSV = new float[3];
            Color.colorToHSV(color, HSV);

            boolean putBlackPixel = HSV[2] <= top;

            realColor = Color.HSVToColor(realHSV);

            if (putBlackPixel) {
                buffOut.put(color);
            } else {
                buffOut.put(realColor);
            }
        }// END WHILE
        dodge.recycle();
        buffOut.rewind();
        base.copyPixelsFromBuffer(buffOut); 

    } catch (Exception e) {
        // TODO: handle exception
    }

    return base;
}

public static float getRoundedValue(float value, int intervalSize) {
        float result = Math.round(value);
        int mod = ((int) result) % intervalSize;
        result += mod < (intervalSize / 2) ? -mod : intervalSize - mod;
        return result;

    }

这一点没有得到改善。如果 和 合并会更好。Apply-ColorColor-Dodge-Blend-Merge

感谢XverhelstX的问答


推荐