Android使用OpenGL和FreeType绘制文字

news2024/11/26 4:28:02

Open GL主要是渲染图形的,有时候需要绘制文字,网上搜了一下,基本思路都是把文字转成位图,再使用Open GL纹理进行渲染。加载纹理在特定阶段才能成功(在onSurfaceCreated中加载),这样就无法动态的绘制字符串,一种方式是把可能用到的字符都加载到一个位图,渲染纹理的时候不同的字符就渲染纹理的特定区域,另一种方式就是每个字符生成一个位图(本文提供的代码就是这种方式)。

1、集成FreeType

这里我们直接使用源码集成 下载FreeType源码

新建一个 Android Native Library 类型的 Module 或者点击 File -> Add C++ to Module,下载的FreeType源码解压后文件夹改成 freetype,然后把整个文件夹复制到 cpp 目录,在 cpp 目录下的 CMakeLists.txt 中添加 freetype:

add_subdirectory(freetype)
target_link_libraries(${CMAKE_PROJECT_NAME}
        # List libraries link to the target library
        android
        log
        freetype)

我建的Module名称是 jfreetype,实现的代码主要有:

jfreetype.cpp

#include <jni.h>
#include <string>
#include <android//log.h>
#include "ft2build.h"
#include FT_FREETYPE_H

#define LOG_I(...) __android_log_print(ANDROID_LOG_INFO, "NDK FT", __VA_ARGS__)
#define LOG_W(...) __android_log_print(ANDROID_LOG_WARN, "NDK FT", __VA_ARGS__)
#define LOG_E(...) __android_log_print(ANDROID_LOG_ERROR, "NDK FT", __VA_ARGS__)

// https://freetype.org/freetype2/docs/tutorial

FT_Library library;   /* handle to library     */
FT_Face face;      /* handle to face object */

extern "C" JNIEXPORT jint JNICALL
Java_site_feiyuliuxing_jfreetype_JFreeType_init(
        JNIEnv *env,
        jobject, jobject face_buffer) {
    std::string hello = "Hello from C++";
    FT_Error error = FT_Init_FreeType(&library);
    if (error) {
        LOG_E("an error occurred during library initialization, error: %d", error);
        return error;
    }
    jbyte *buffer = (jbyte *) (env->GetDirectBufferAddress(face_buffer));
    jlong size = env->GetDirectBufferCapacity(face_buffer);
    error = FT_New_Memory_Face(library,
                               (FT_Byte *) buffer,    /* first byte in memory */
                               size,      /* size in bytes        */
                               0,         /* face_index           */
                               &face);
    if (error) {
        LOG_E("an error occurred during FT_New_Memory_Face, error: %d", error);
        return error;
    }
    error = FT_Set_Pixel_Sizes(
            face,   /* handle to face object */
            0,      /* pixel_width           */
            128);   /* pixel_height          */
    if (error) {
        LOG_E("an error occurred during FT_Set_Pixel_Sizes, error: %d", error);
        return error;
    }
    return 0;
}


extern "C"
JNIEXPORT jint JNICALL
Java_site_feiyuliuxing_jfreetype_JFreeType_charBitmap(
        JNIEnv *env, jobject thiz,
        jobject ft_bitmap, jchar charcode) {
    FT_UInt glyph_index = FT_Get_Char_Index(face, charcode);
    FT_Error error = FT_Load_Glyph(
            face,          /* handle to face object */
            glyph_index,   /* glyph index           */
            FT_LOAD_DEFAULT);  /* load flags, see below */
    if (error) {
        LOG_E("an error occurred during FT_Get_Char_Index, error: %d", error);
        return error;
    }
    error = FT_Render_Glyph(face->glyph,   /* glyph slot  */
                            FT_RENDER_MODE_NORMAL); /* render mode */
    if (error) {
        LOG_E("an error occurred during FT_Render_Glyph, error: %d", error);
        return error;
    }
    FT_Bitmap bitmap = face->glyph->bitmap;

    LOG_I("--------------- %c ---------------", charcode);
    LOG_I("FT_Bitmap size: %d x %d", bitmap.width, bitmap.rows);
    LOG_I("FT_Bitmap pixel mode: %d", bitmap.pixel_mode);
    LOG_I("FT_Bitmap bitmap top: %d", face->glyph->bitmap_top);
    LOG_I("metrics.height: %ld", face->glyph->metrics.height);
    LOG_I("metrics.horiBearingY: %ld", face->glyph->metrics.horiBearingY);

    jclass bmpCls = env->GetObjectClass(ft_bitmap);
    jfieldID rowsID = env->GetFieldID(bmpCls, "rows", "I");
    jfieldID widthID = env->GetFieldID(bmpCls, "width", "I");
    jfieldID bufferID = env->GetFieldID(bmpCls, "buffer", "[B");
    jfieldID leftID = env->GetFieldID(bmpCls, "bitmapLeft", "I");
    jfieldID topID = env->GetFieldID(bmpCls, "bitmapTop", "I");

    env->SetIntField(ft_bitmap, rowsID, (int) bitmap.rows);
    env->SetIntField(ft_bitmap, widthID, (int) bitmap.width);
    env->SetIntField(ft_bitmap, leftID, face->glyph->bitmap_left);
    env->SetIntField(ft_bitmap, topID, face->glyph->bitmap_top);

    int dataLength = bitmap.rows * bitmap.width;
    jbyteArray buf = env->NewByteArray(dataLength);
    jbyte *data = env->GetByteArrayElements(buf, nullptr);

    for (int i = 0; i < dataLength; ++i) {
        data[i] = bitmap.buffer[i];
    }
    env->ReleaseByteArrayElements(buf, data, 0);
    env->SetObjectField(ft_bitmap, bufferID, buf);

    return 0;
}


extern "C"
JNIEXPORT void JNICALL
Java_site_feiyuliuxing_jfreetype_JFreeType_close(JNIEnv *env, jobject thiz) {
    FT_Done_FreeType(library);
}

FTBitmap.kt

import android.graphics.Bitmap
import android.graphics.Color

class FTBitmap @JvmOverloads constructor(
    var rows: Int = 0,
    var width: Int = 0,
    var buffer: ByteArray? = null,
    var bitmapLeft: Int = 0,
    var bitmapTop: Int = 0,
) {
    fun toBitmap(maxAscent: Int, maxDescent: Int): Bitmap? {
        if (buffer == null) return null

        val xOffset = bitmapLeft
        val yOffset = maxAscent - bitmapTop
        val width = this.width + xOffset
        val height = rows + yOffset + maxDescent - (rows - bitmapTop)

        val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
        for (y in 0 until rows) {
            for (x in 0 until this.width) {
                val index = y * this.width + x
                val pixelValue = buffer!![index].toInt() and 0xff
                bitmap.setPixel(x + xOffset, y + yOffset, Color.rgb(pixelValue, pixelValue, pixelValue))
            }
        }
        return bitmap
    }
}

 JFreeType.kt

package site.feiyuliuxing.jfreetype

import java.nio.ByteBuffer

class JFreeType {

    /**
     * A native method that is implemented by the 'jfreetype' native library,
     * which is packaged with this application.
     */
    external fun init(faceBuffer: ByteBuffer): Int

    external fun charBitmap(ftBitmap: FTBitmap, char: Char): Int

    external fun close()

    companion object {
        // Used to load the 'jfreetype' library on application startup.
        init {
            System.loadLibrary("jfreetype")
        }
    }
}

至此,我们需要的接口都已经准备好啦,继续~~

2、使用Open GL绘制文字

Android Open GL基础这里就不介绍了,如有需要,可以参考构建OpenGL ES环境

需要准备一个字体文件,可以自己搜索下载一个ttf,替换后面代码中的“SourceCodePro-Regular.ttf”

GLUtil.kt

import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.opengl.GLES11Ext.GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT
import android.opengl.GLES11Ext.GL_TEXTURE_MAX_ANISOTROPY_EXT
import android.opengl.GLES30.*
import android.opengl.GLUtils
import android.util.Log
import androidx.annotation.DrawableRes
import java.nio.ByteBuffer

object GLUtil {
    private const val TAG = "GLUtil"

    fun createShaderProgram(vertexShaderSource: String, fragmentShaderSource: String): Int {
        val vShader = glCreateShader(GL_VERTEX_SHADER)
        val fShader = glCreateShader(GL_FRAGMENT_SHADER)
        glShaderSource(vShader, vertexShaderSource)
        glShaderSource(fShader, fragmentShaderSource)

        val status = IntArray(1)

        glCompileShader(vShader)
        checkOpenGLError()
        glGetShaderiv(vShader, GL_COMPILE_STATUS, status, 0)
        if (status[0] != 1) {
            Log.e(TAG, "vertex compilation failed")
            printShaderLog(vShader)
        }

        glCompileShader(fShader)
        checkOpenGLError()
        glGetShaderiv(fShader, GL_COMPILE_STATUS, status, 0)
        if (status[0] != 1) {
            Log.e(TAG, "fragment compilation failed")
            printShaderLog(fShader)
        }

        val vfProgram = glCreateProgram()
        glAttachShader(vfProgram, vShader)
        glAttachShader(vfProgram, fShader)
        glLinkProgram(vfProgram)
        checkOpenGLError()
        glGetProgramiv(vfProgram, GL_LINK_STATUS, status, 0)
        if (status[0] != 1) {
            Log.e(TAG, "linking failed")
            printProgramLog(vfProgram)
        }
        return vfProgram
    }

    private fun printShaderLog(shader: Int) {
        val len = IntArray(1)
        glGetShaderiv(shader, GL_INFO_LOG_LENGTH, len, 0)
        if (len[0] > 0) {
            val log = glGetShaderInfoLog(shader)
            Log.e(TAG, "Shader Info Log: $log")
        }
    }

    private fun printProgramLog(prog: Int) {
        val len = IntArray(1)
        glGetProgramiv(prog, GL_INFO_LOG_LENGTH, len, 0)
        Log.e(TAG, "printProgramLog() - log length=${len[0]}")
        if (len[0] > 0) {
            val log = glGetProgramInfoLog(prog)
            Log.e(TAG, "Program Info Log: $log")
        }
    }

    private fun checkOpenGLError(): Boolean {
        var foundError = false
        var glErr = glGetError()
        while (glErr != GL_NO_ERROR) {
            Log.e(TAG, "glError: $glErr")
            foundError = true
            glErr = glGetError()
        }
        return foundError
    }

    fun Context.loadTexture(@DrawableRes img: Int): Int {
        val options = BitmapFactory.Options()
        options.inScaled = false
        val bitmap = BitmapFactory.decodeResource(resources, img, options)
        return loadTexture(bitmap)
    }

    fun loadTexture(bitmap: Bitmap): Int {
        Log.d(TAG, "bitmap size: ${bitmap.width} x ${bitmap.height}")

        val textures = IntArray(1)
        glGenTextures(1, textures, 0)
        val textureID = textures[0]
        if (textureID == 0) {
            Log.e(TAG, "Could not generate a new OpenGL textureId object.")
            return 0
        }
        glBindTexture(GL_TEXTURE_2D, textureID)

        // https://developer.android.google.cn/reference/android/opengl/GLES20#glTexImage2D(int,%20int,%20int,%20int,%20int,%20int,%20int,%20int,%20java.nio.Buffer)
        /*      int target,
                int level,
                int internalformat,
                int width,
                int height,
                int border,
                int format,
                int type,
                Buffer pixels */
        val pixels = ByteBuffer.allocateDirect(bitmap.byteCount)
        bitmap.copyPixelsToBuffer(pixels)
        pixels.position(0)//这步比较关键,不然无法加载纹理数据

        val internalformat = GLUtils.getInternalFormat(bitmap)
        val type = GLUtils.getType(bitmap)
//        Log.i(TAG, "internalformat=$internalformat, GL_RGBA=$GL_RGBA")
//        Log.i(TAG, "type=$type, GL_UNSIGNED_BYTE=$GL_UNSIGNED_BYTE")
//        glTexImage2D(GL_TEXTURE_2D, 0, internalformat, bitmap.width, bitmap.height, 0, internalformat, type, pixels)
        GLUtils.texImage2D(GL_TEXTURE_2D, 0, bitmap, 0)

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)
        glGenerateMipmap(GL_TEXTURE_2D)

        val ext = glGetString(GL_EXTENSIONS)
//        Log.e(TAG, ext)
        if (ext.contains("GL_EXT_texture_filter_anisotropic")) {
            val anisoset = FloatArray(1)
            glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, anisoset, 0)
            Log.d(TAG, "anisoset=${anisoset[0]}")
            glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisoset[0])
        }
        bitmap.recycle()
        return textureID
    }
}

GLChar.kt

import android.graphics.Bitmap
import android.opengl.GLES30.*
import java.nio.ByteBuffer
import java.nio.ByteOrder

class GLChar(bitmap: Bitmap) {
    private var positionVertex = FloatArray(15)

    private val vertexBuffer = ByteBuffer.allocateDirect(positionVertex.size * 4)
        .order(ByteOrder.nativeOrder())
        .asFloatBuffer()
        .put(positionVertex)
        .apply{ position(0) }

    private val texVertexBuffer = ByteBuffer.allocateDirect(TEX_VERTEX.size * 4)
        .order(ByteOrder.nativeOrder())
        .asFloatBuffer()
        .put(TEX_VERTEX)
        .position(0)

    private val vertexIndexBuffer = ByteBuffer.allocateDirect(VERTEX_INDEX.size * 2)
        .order(ByteOrder.nativeOrder())
        .asShortBuffer()
        .put(VERTEX_INDEX)
        .position(0)

    private var textureId = 0

    var glWidth: Float = 0f
        private set
    var glHeight: Float = 0f
        private set

    init {
        textureId = GLUtil.loadTexture(bitmap)

        val cx = 0f
        val cy = 0f
        val xOffset = 0.0005f * bitmap.width
        val yOffset = 0.0005f * bitmap.height

        glWidth = xOffset * 2f
        glHeight = yOffset * 2f

        positionVertex = floatArrayOf(
            cx, cy, 0f,
            xOffset, yOffset, 0f,
            -xOffset, yOffset, 0f,
            -xOffset, -yOffset, 0f,
            xOffset, -yOffset, 0f
        )
        vertexBuffer.position(0)
        vertexBuffer.put(positionVertex)
        vertexBuffer.position(0)
    }

    fun draw(vbo: IntArray) {
        glBindBuffer(GL_ARRAY_BUFFER, vbo[0])
        glBufferData(GL_ARRAY_BUFFER, vertexBuffer.capacity() * 4, vertexBuffer, GL_STATIC_DRAW)
        glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0)
        glEnableVertexAttribArray(0)

        glBindBuffer(GL_ARRAY_BUFFER, vbo[1])
        glBufferData(GL_ARRAY_BUFFER, texVertexBuffer.capacity() * 4, texVertexBuffer, GL_STATIC_DRAW)
        glVertexAttribPointer(1, 2, GL_FLOAT, false, 0, 0)
        glEnableVertexAttribArray(1)
        //激活纹理
        glActiveTexture(GL_TEXTURE0)
        //绑定纹理
        glBindTexture(GL_TEXTURE_2D, textureId)
        // 绘制
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[2])
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, VERTEX_INDEX.size * 2, vertexIndexBuffer, GL_STATIC_DRAW)
        glDrawElements(GL_TRIANGLES, VERTEX_INDEX.size, GL_UNSIGNED_SHORT, 0)
    }

    companion object {
        private const val TAG = "GLChar"

        /**
         * 绘制顺序索引
         */
        private val VERTEX_INDEX = shortArrayOf(
            0, 1, 2,  //V0,V1,V2 三个顶点组成一个三角形
            0, 2, 3,  //V0,V2,V3 三个顶点组成一个三角形
            0, 3, 4,  //V0,V3,V4 三个顶点组成一个三角形
            0, 4, 1   //V0,V4,V1 三个顶点组成一个三角形
        )

        /**
         * 纹理坐标
         * (s,t)
         */
        private val TEX_VERTEX = floatArrayOf(
            0.5f, 0.5f, //纹理坐标V0
            1f, 0f,     //纹理坐标V1
            0f, 0f,     //纹理坐标V2
            0f, 1.0f,   //纹理坐标V3
            1f, 1.0f    //纹理坐标V4
        )
    }
}

 GLText.tk

class GLText(text: String, glChars: Map<Char, GLChar>) {
    private val glCharList = mutableListOf<GLChar>()

    init {
        for (c in text) glChars[c]?.let(glCharList::add)
    }

    fun draw(vbo: IntArray, offsetBlock: (Float, Float)->Unit) {
        val textWidth = glCharList.sumOf { it.glWidth.toDouble() }.toFloat()
        var xOffset = -textWidth / 2f

        for (glChar in glCharList) {
            offsetBlock(xOffset, 0f)
            glChar.draw(vbo)
            xOffset += glChar.glWidth
        }
    }
}

RendererText.kt

import android.content.Context
import android.opengl.GLES30.*
import android.opengl.GLSurfaceView
import android.opengl.Matrix
import java.nio.ByteBuffer
import javax.microedition.khronos.egl.EGLConfig
import javax.microedition.khronos.opengles.GL10

class RendererText(private val context: Context) : GLSurfaceView.Renderer, IShaderProvider {
    private val numVAOs = 1
    private val numVBOs = 3

    private val vao = IntArray(numVAOs)
    private val vbo = IntArray(numVBOs)

    private var cameraX = 0f
    private var cameraY = 0f
    private var cameraZ = 2.5f

    private var renderingProgram = 0
    private var mvLoc = 0
    private var projLoc = 0

    private val pMat = FloatArray(16)
    private val vMat = FloatArray(16)
    private val mMat = FloatArray(16)
    private val mvMat = FloatArray(16)

    private val glChars = mutableMapOf<Char, GLChar>()
    private var glText = GLText("", glChars)

    private fun loadGLChars() {
        val ft = JFreeType()
        val faceBuffer = context.assets.open("fonts/SourceCodePro-Regular.ttf").use {
            ByteBuffer.allocateDirect(it.available())
                .put(it.readBytes()).apply { position(0) }
        }
        ft.init(faceBuffer)

        val chars = mutableListOf<Char>()
        fun putChar(char: Char) {
            chars.add(char)
        }

        fun putChars(range: IntRange) {
            for (charcode in range) putChar(charcode.toChar())
        }
        putChars('A'.code..'Z'.code)
        putChars('a'.code..'z'.code)
        putChars('0'.code..'9'.code)
        putChar('!')

        val ftBitmaps = chars.map {
            val ftBitmap = FTBitmap()
            ft.charBitmap(ftBitmap, it)
            ftBitmap
        }

        var maxAscent = 0
        var maxDescent = 0
        for (ftBmp in ftBitmaps) {
            if (ftBmp.bitmapTop > maxAscent) maxAscent = ftBmp.bitmapTop
            if (ftBmp.rows - ftBmp.bitmapTop > maxDescent) maxDescent = ftBmp.rows - ftBmp.bitmapTop
        }

        for (i in chars.indices) {
            ftBitmaps[i].toBitmap(maxAscent, maxDescent)?.let { bitmap ->
                glChars[chars[i]] = GLChar(bitmap)
            }
        }

        ft.close()

        glText = GLText("HelloWorld!", glChars)
    }

    override fun onSurfaceCreated(p0: GL10?, p1: EGLConfig?) {
        renderingProgram = GLUtil.createShaderProgram(vertexShaderSource(), fragmentShaderSource())
        glUseProgram(renderingProgram)
        mvLoc = glGetUniformLocation(renderingProgram, "mv_matrix")
        projLoc = glGetUniformLocation(renderingProgram, "proj_matrix")
        glGenVertexArrays(1, vao, 0)
        glBindVertexArray(vao[0])
        glGenBuffers(numVBOs, vbo, 0)
        loadGLChars()
    }

    override fun onSurfaceChanged(p0: GL10?, width: Int, height: Int) {
        glViewport(0, 0, width, height)
        val aspect = width.toFloat() / height.toFloat()
        Matrix.perspectiveM(pMat, 0, Math.toDegrees(1.0472).toFloat(), aspect, 0.1f, 1000f)
    }

    override fun onDrawFrame(p0: GL10?) {
        glClearColor(0f, 0f, 0f, 1f)
        glClear(GL_COLOR_BUFFER_BIT)
        //下面两行代码,防止图片的透明部分被显示成黑色
        glEnable(GL_BLEND)
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

        Matrix.setIdentityM(vMat, 0)
        Matrix.translateM(vMat, 0, -cameraX, -cameraY, -cameraZ)
        Matrix.setIdentityM(mMat, 0)
        Matrix.multiplyMM(mvMat, 0, vMat, 0, mMat, 0)

        glUniformMatrix4fv(mvLoc, 1, false, mvMat, 0)
        glUniformMatrix4fv(projLoc, 1, false, pMat, 0)

        glText.draw(vbo) { xOffset, yOffset ->
            Matrix.setIdentityM(mMat, 0)
            Matrix.translateM(mMat, 0, xOffset, yOffset, 0f)
            Matrix.multiplyMM(mvMat, 0, vMat, 0, mMat, 0)
            glUniformMatrix4fv(mvLoc, 1, false, mvMat, 0)
        }
    }

    override fun vertexShaderSource(): String {
        return """
            #version 300 es

            layout (location = 0) in vec3 position;
            layout (location = 1) in vec2 tex_coord;
            out vec2 tc;

            uniform mat4 mv_matrix;
            uniform mat4 proj_matrix;
            uniform sampler2D s;

            void main(void)
            {
            	gl_Position = proj_matrix * mv_matrix * vec4(position, 1.0);
            	tc = tex_coord;
            }
        """.trimIndent()
    }

    override fun fragmentShaderSource(): String {
        return """
            #version 300 es
            precision mediump float;
            in vec2 tc;
            out vec4 color;

            uniform sampler2D s;

            void main(void)
            {
            	color = texture(s,tc);
            }
        """.trimIndent()
    }
}

效果图

3、总结

字符转位图,照着FreeType的文档很容易就实现了,其中关于字符水平对齐稍微花了点时间,后结合文档Managing Glyphs以及观察打印的数据,确定 bitmap_left 就是 bearingX,bitmap_top 是 bearingY,这样很容易把水平方向的字符按照 baseline 对齐。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1494140.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Cocos Creator 3.8.x 制作模糊效果(比如游戏弹窗需要的模糊效果)

接着上一个讨论的话题,关于3.8.x的后效,今天来分享自定义后效来制作模糊效果,并将他应用到弹窗中做背景,话不多说开整。 一:最终效果 首先咱们来看官网自定义后效怎么搞的,从它的实例开始:自定义后效 二:定义PostProcessSettings给节点提供资源(通过编辑器修改参数的…

【JavaScript】Map、Reduce 和 Filter - 通过代码示例解释 JS 数组函数

Map、reduce 和 filter 都是 JavaScript 中的数组方法。每个都将迭代一个数组并执行转换或计算。每个函数都会根据函数的结果返回一个新数组。在本文中&#xff0c;您将了解为什么以及如何使用每一个。 以下是 Steven Luscher 的有趣总结&#xff1a; Map map()方法用于从现…

抖音开店实操步骤,图文详解!

大家好&#xff0c;我是电商糖果 话不多说&#xff0c;最近准备在抖音开店的朋友&#xff0c;这份图文开店笔记&#xff0c;记得收藏&#xff01; 一、开店前的准备 1. 营业执照 执照最好选个体的&#xff0c;个体执照可以直接去工商局办理&#xff0c;也可以找专业的代办。…

2024/3/5打卡最长上升子序列**----线性DP,贪心,单调栈

目录 题目&#xff1a; DP分析&#xff1a; 代码&#xff1a; 3.6更新 贪心 第一个思考方式 先上代码&#xff1a; 解析&#xff1a; 贪心 第二个思考方式 &#xff08;与上面的思路差不多&#xff0c;但是换了个角度&#xff09; 思路&#xff1a; 代码&#xff1a; …

探索神经网络在商品销售和图像识别中的应用

目录 前言人工神经网络简介1.1 人工神经网络与深度学习简介1.2 生物神经元结构与神经元机器模型1.3 神经网络的数据量与性能关系 2 需求预测2.1 需求预测的背景2.2 商品销售神经元机器模型2.3 多层神经网络结构的优势 3 图像识别3.1 图像识别神经网络技术3.2 实际应用场景 结语…

AI领域再出“王炸“----Claude3是否会成为下一个“神“

目录 一.Claude3最新发布 二.Claude3支持20万token 三.Claude3在未公开算法上取得重大突破 1.Claude 3读懂博士论文 2.量子跃迁集成&#xff1a; Claude 3智商&#xff1a;101 测试方法 测试细节 通过Karpathy挑战 Claude 3自画像&#xff0c;突破本我 从洛杉矶排到…

3_1储能容量配置

% 创建优化问题 problem optimproblem(ObjectiveSense, minimize);% 定义变量 x optimvar(x, 2, 1, LowerBound, 0); % 储能设备容量变量% 定义目标函数 problem.Objective 2*x(1) 3*x(2); % 假设成本函数为2*x1 3*x2% 定义约束条件 problem.Constraints.capacity1 x(1) …

01-环境搭建、SpringCloud微服务(注册发现、服务调用、网关)

环境搭建、SpringCloud微服务(注册发现、服务调用、网关) 1)课程对比 2)项目概述 2.1)能让你收获什么 2.2)项目课程大纲 2.3)项目概述 随着智能手机的普及&#xff0c;人们更加习惯于通过手机来看新闻。由于生活节奏的加快&#xff0c;很多人只能利用碎片时间来获取信息&…

画图解题思路( ccf 201512-3)

分析 首先需要转换坐标系&#xff0c;可以将两个坐标系的点写出来&#xff0c;对比一下找规律 可以发现题目中的坐标(x, y)转变成数组坐标系为(n - y - 1, x); 然后再判断是画线还是填充 画线&#xff1a;先转换题目坐标&#xff0c;再遍历画线 填充&#xff1a;采用dfs

Vue中有哪些优化性能的方法?

Vue是一款流行的JavaScript框架&#xff0c;用于构建交互性强的Web应用程序。在前端开发中&#xff0c;性能优化是一个至关重要的方面&#xff0c;尤其是当应用程序规模变大时。Vue提供了许多优化性能的方法&#xff0c;可以帮助开发人员提升应用程序的性能&#xff0c;从而提升…

LABEL-EFFICIENT SEMANTIC SEGMENTATION WITHDIFFUSION MODELS

基于扩散模型的标签高效语义分割 摘要&#xff1a; 去噪扩散概率模型最近受到了很多研究的关注&#xff0c;因为它们优于gan等替代方法&#xff0c;并且目前提供了最先进的生成性能。扩散模型的优越性能使其成为一些应用程序的吸引人的工具&#xff0c;包括绘图&#xff0c;超…

【Python】3. 基础语法(2)

顺序语句 默认情况下, Python 的代码执行顺序是按照从上到下的顺序, 依次执行的. print("1") print("2") print("3")执行结果一定为 “123”, 而不会出现 “321” 或者 “132” 等. 这种按照顺序执行的代码, 我们称为 顺序语句. 这个顺序是很关…

使用php_screw实现PHP代码加密

一&#xff1a;php_screw下载地址 https://gitee.com/splot/php-screw-plus https://github.com/del-xiong/screw-plus 二&#xff1a;php_screw安装 1&#xff1a;解压并修改加密key unzip php-screw-plus-master.zip cd php-screw-plus-master 打开php-screw-plus-mast…

【Docker】技术架构演变

【Docker】技术架构演变 目录 【Docker】技术架构演变架构中的概念架构演进单机架构相关软件 应用数据分离架构应用服务集群架构相关软件 读写分离/主从分离架构相关软件 引入缓存——冷热分离架构相关软件 垂直分库&#xff08;分布式数据库架构&#xff09;相关软件 业务拆分…

力扣--动态规划516.最长回文子序列

思路分析&#xff1a; 创建一个二维动态规划表dp&#xff0c;其中dp[i][j]表示在子串s[i...j]中的最长回文子序列的长度。初始化基本情况&#xff1a;对角线上的元素dp[i][i]都为1&#xff0c;因为单个字符本身就是长度为1的回文子序列。从字符串末尾向前遍历&#xff0c;填充…

Java Day2 面向对象

这里写目录标题 1、static总结1.1 代码块1.1.1 静态代码块1.1.2 实例代码块1.1.3 小例子 2、继承2.1 权限修饰符2.2 方法重写2.3 子类访问成员特点2.4子类构造器的特点 3、多态4、final、常量4.1 final4.2 常量 5 抽象类5.1 概念5.2 模板设计方法 6、接口6.1 接口新方法6.2 接口…

Java工程师必备知识,系列教学

一、前言 在这里我不得不感慨Spring的代码的完善与优秀&#xff0c;从之前看源码迷迷糊糊到现在基本了解Spring的部分源码后&#xff0c;愈来愈发现Spring开发者的思虑之周全&#xff01; 之前说过学习源码的目的在哪&#xff1f;正如我特别喜欢的一句话&#xff0c;有道无术…

进口及国内细胞分析仪厂家名录大全-贝克曼、安捷伦、希森美康、迈瑞.....

流式细胞仪是一种测量层流中细胞的设备&#xff08;细胞仪&#xff09;&#xff0c;其通过将每个细胞排列在鞘液中&#xff0c;加以激光束照射&#xff0c;可测量散射光和荧光&#xff0c;从而获得有关每个细胞的信息&#xff0c;包含细胞结构&#xff08;如大小、粒度、表面积…

移动开发:网格视图

一、在新建GridView模块下添加图片以及创建cell.xml文件 1.粘贴图片时选择红框中的路径&#xff0c;点击“OK” 2.在路径后添加-mdpi后缀,再点击“OK” 二、相关代码块 1.MainActivity.java文件代码 package com.example.gridview;import androidx.appcompat.app.AppCompatAc…

指针的学习4

目录 回调函数 qsort使用样例 使用qsort函数排序整形数据 使用qsort函数排序结构体 回调函数 回调函数就是一个通过函数指针调用的函数。如果把函数的指针&#xff08;地址&#xff09;作为参数传递给另一个函数&#xff0c;当这个指针被用来调用其所指向的函数时&#xf…