在Java/Android中在画布上创建具有深度/3D外观的形状

3
请看下面的图片。Flat是输入,输出应该是底部的图片,显示直线和曲线的深度或3D外观。尝试了EmbossMaskFilter,但由于光线问题,它不能给出相同的输出。
我列出了生成所需输出的c#代码。问题是如何在Java / Android中实现类似的功能,特别是在移动设备上需要快速处理画布绘制。

enter image description here

 Bitmap modifiedPiecePicture = (Bitmap)piecePicture.Clone();
                     ImageUtilities.EdgeDetectHorizontal(modifiedPiecePicture);
                    ImageUtilities.EdgeDetectVertical(modifiedPiecePicture);
                    piecePicture = ImageUtilities.AlphaBlendMatrix(modifiedPiecePicture, piecePicture, 200);

public static bool EdgeDetectHorizontal(Bitmap b)
        {
            Bitmap bmTemp = (Bitmap)b.Clone();

            // GDI+ still lies to us - the return format is BGR, NOT RGB.
            BitmapData bmData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            BitmapData bmData2 = bmTemp.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

            int stride = bmData.Stride;
            System.IntPtr Scan0 = bmData.Scan0;
            System.IntPtr Scan02 = bmData2.Scan0;

            unsafe
            {
                byte* p = (byte*)(void*)Scan0;
                byte* p2 = (byte*)(void*)Scan02;

                int nOffset = stride - b.Width * 3;
                int nWidth = b.Width * 3;

                int nPixel = 0;

                p += stride;
                p2 += stride;

                for (int y = 1; y < b.Height - 1; ++y)
                {
                    p += 9;
                    p2 += 9;

                    for (int x = 9; x < nWidth - 9; ++x)
                    {
                        nPixel = ((p2 + stride - 9)[0] +
                            (p2 + stride - 6)[0] +
                            (p2 + stride - 3)[0] +
                            (p2 + stride)[0] +
                            (p2 + stride + 3)[0] +
                            (p2 + stride + 6)[0] +
                            (p2 + stride + 9)[0] -
                            (p2 - stride - 9)[0] -
                            (p2 - stride - 6)[0] -
                            (p2 - stride - 3)[0] -
                            (p2 - stride)[0] -
                            (p2 - stride + 3)[0] -
                            (p2 - stride + 6)[0] -
                            (p2 - stride + 9)[0]);

                        if (nPixel < 0) nPixel = 0;
                        if (nPixel > 255) nPixel = 255;

                        (p + stride)[0] = (byte)nPixel;

                        ++p;
                        ++p2;
                    }

                    p += 9 + nOffset;
                    p2 += 9 + nOffset;
                }
            }

            b.UnlockBits(bmData);
            bmTemp.UnlockBits(bmData2);

            return true;
        }

        public static bool EdgeDetectVertical(Bitmap b)
        {
            Bitmap bmTemp = (Bitmap)b.Clone();

            // GDI+ still lies to us - the return format is BGR, NOT RGB.
            BitmapData bmData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            BitmapData bmData2 = bmTemp.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

            int stride = bmData.Stride;
            System.IntPtr Scan0 = bmData.Scan0;
            System.IntPtr Scan02 = bmData2.Scan0;

            unsafe
            {
                byte* p = (byte*)(void*)Scan0;
                byte* p2 = (byte*)(void*)Scan02;

                int nOffset = stride - b.Width * 3;
                int nWidth = b.Width * 3;

                int nPixel = 0;

                int nStride2 = stride * 2;
                int nStride3 = stride * 3;

                p += nStride3;
                p2 += nStride3;

                for (int y = 3; y < b.Height - 3; ++y)
                {
                    p += 3;
                    p2 += 3;

                    for (int x = 3; x < nWidth - 3; ++x)
                    {
                        nPixel = ((p2 + nStride3 + 3)[0] +
                            (p2 + nStride2 + 3)[0] +
                            (p2 + stride + 3)[0] +
                            (p2 + 3)[0] +
                            (p2 - stride + 3)[0] +
                            (p2 - nStride2 + 3)[0] +
                            (p2 - nStride3 + 3)[0] -
                            (p2 + nStride3 - 3)[0] -
                            (p2 + nStride2 - 3)[0] -
                            (p2 + stride - 3)[0] -
                            (p2 - 3)[0] -
                            (p2 - stride - 3)[0] -
                            (p2 - nStride2 - 3)[0] -
                            (p2 - nStride3 - 3)[0]);

                        if (nPixel < 0) nPixel = 0;
                        if (nPixel > 255) nPixel = 255;

                        p[0] = (byte)nPixel;

                        ++p;
                        ++p2;
                    }

                    p += 3 + nOffset;
                    p2 += 3 + nOffset;
                }
            }

            b.UnlockBits(bmData);
            bmTemp.UnlockBits(bmData2);

            return true;
        }

        public static Bitmap AlphaBlendMatrix(Bitmap destImage, Bitmap srcImage, byte alpha)
        {            
            Bitmap alphaBlendedImage = (Bitmap)destImage.Clone();

            // for the matrix the range is 0.0 - 1.0
            float alphaNorm = (float)alpha / 255.0F;

            // just change the alpha
            ColorMatrix matrix = new ColorMatrix(new float[][]{
                            new float[] {1F, 0, 0, 0, 0},
                            new float[] {0, 1F, 0, 0, 0},
                            new float[] {0, 0, 1F, 0, 0},
                            new float[] {0, 0, 0, alphaNorm, 0},
                            new float[] {0, 0, 0, 0, 1F}});

            ImageAttributes imageAttributes = new ImageAttributes();
            imageAttributes.SetColorMatrix(matrix);

            int offsetX = (destImage.Width - srcImage.Width) / 2;
            int offsetY = (destImage.Height - srcImage.Height) / 2;

            using (Graphics g = Graphics.FromImage(alphaBlendedImage))
            {
                g.CompositingMode = CompositingMode.SourceOver;
                g.CompositingQuality = CompositingQuality.HighQuality;

                // Scaled image (stretched)
                //g.DrawImage(srcImage,
                //    new Rectangle(0, 0, destImage.Width, destImage.Height),
                //    0,
                //    0,
                //    srcImage.Width,
                //    srcImage.Height,
                //    GraphicsUnit.Pixel,
                //    imageAttributes);

                // No scaling
                g.DrawImage(srcImage,
                    new Rectangle(offsetX, offsetY, srcImage.Width, srcImage.Height),
                    0,
                    0,
                    srcImage.Width,
                    srcImage.Height,
                    GraphicsUnit.Pixel,
                    imageAttributes);
            }

            return alphaBlendedImage;
        }
2个回答

0

3D立方体代码在这里,将其粘贴到CustomView类中

功能

private fun drawCube(
    x: Int,
    y: Int,
    width: Int,
    height: Int,
    paint: Paint,
    canvas: Canvas
) {
    val p1 = Point(x, y)
    val p2 = Point(x, y + height)
    val p3 = Point(x + width, y + height)
    val p4 = Point(x + width, y)
    val p5 = Point(x + width / 2, y - height / 2)
    val p6 = Point(x + 3 * width / 2, y - height / 2)
    val p7 = Point(x + 3 * width / 2, y + height / 2)

    val path = Path()
    path.fillType = Path.FillType.EVEN_ODD
    path.moveTo(p1.x.toFloat(), p1.y.toFloat())
    path.lineTo(p2.x.toFloat(), p2.y.toFloat())
    path.lineTo(p3.x.toFloat(), p3.y.toFloat())
    path.lineTo(p4.x.toFloat(), p4.y.toFloat())
    path.lineTo(p1.x.toFloat(), p1.y.toFloat())
    path.lineTo(p5.x.toFloat(), p5.y.toFloat())
    path.lineTo(p6.x.toFloat(), p6.y.toFloat())
    path.lineTo(p4.x.toFloat(), p4.y.toFloat())
    path.moveTo(p3.x.toFloat(), p3.y.toFloat())
    path.lineTo(p7.x.toFloat(), p7.y.toFloat())
    path.lineTo(p6.x.toFloat(), p6.y.toFloat())
    path.lineTo(p4.x.toFloat(), p4.y.toFloat())
    path.close()
    canvas.drawPath(path, paint)

}

将此行粘贴到onDraw重写方法中

drawCube(
                    fp.mX.toInt(), fp.mY.toInt(),
                    100 + (fp.mCx.toInt() - fp.mX.toInt()),
                    100 + fp.mCy.toInt() - fp.mY.toInt(),
                    mPaint, mCanvas!!
                )

//这是用于描边(边框)的

drawCube(
                    fp.mX.toInt(), fp.mY.toInt(),
                    100 + (fp.mCx.toInt() - fp.mX.toInt()),
                    100 + fp.mCy.toInt() - fp.mY.toInt(),
                    mStrokePaint, mCanvas!!
                )

0

快速查看您的代码,显示出典型的图像处理类型行为。我建议查看RenderScript,这是Android的高性能计算框架。虽然您仍需要Java端来显示您的位图,但您的边缘检测代码将全部在RenderScript中。基本上,您会让框架处理并行性- http://android-developers.blogspot.com/2012/01/levels-in-renderscript.html

如果您需要在旧设备上使用它-它可以在Android Support Library中获得。

观看有关此主题的Google IO视频可能会有所帮助:https://youtu.be/uzBw6AWCBpU


谢谢您的回复。您能否列出我需要使用哪些类型的函数来获得所需的输出?上述算法并不完美,因为输出有点模糊。我想要的是一种在Android画布上获得类似/改进的绘图效果的方法。 - pats

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接