Resumen del uso de opencv de python

Como uno de los lenguajes más fáciles de usar, Python tiene una gran cantidad de bibliotecas de terceros. La existencia de estas bibliotecas de terceros permite que muchas personas se concentren en la lógica empresarial y la lógica matemática mientras ignoran las tediosas operaciones de código. -La biblioteca de fiestas es una de ellas.

1. Instalación y uso sencillo de librerías de terceros

Instalar

Una simple instalación de pip es suficiente.El uso de la biblioteca opencv a menudo implica algunas operaciones matriciales, por lo que numpy puede considerarse como una familia con él.

pip install opencv-python

Después de la instalación, simplemente puede abrir la imagen, abrir el video, hagamos un experimento simple:

leer fotos

import cv2

# 读取图像,第一种是正常读取,第二种是读取灰度图像
img = cv2.imread(r"D:\img\among.png")
gray = cv2.imread(r"D:\img\among.png", 0)
# 显示图像
cv2.imshow("colorful", img)
cv2.imshow("gray", gray)
# 不再等待键盘输入事件,直接显示
cv2.waitKey(0)
# 关闭所有显示窗口
cv2.destroyAllWindows()

El efecto de visualización es el siguiente:
inserte la descripción de la imagen aquí
lea el video y reprodúzcalo

import cv2

# 读取视频
video = cv2.VideoCapture('badapple_color.mp4')
# 获取视频对象的帧数
fps = video.get(cv2.CAP_PROP_FPS)
# 设定循环条件
while(video.isOpened()):
    _, frame = video.read()
    cv2.imshow("video", frame)
    # 设置退出条件是输入'q'
    if cv2.waitKey(int(fps)) in [ord('q'), 27]:
            break
cv2.destroyAllWindows()
video.release()

Nota: La reproducción aquí no tiene la barra de progreso y el audio como un reproductor normal, porque aquí están todos los fotogramas del video leído, y luego se reproduce en un bucle, y el audio no se lee y se establece la condición de salida. para entrar q.
inserte la descripción de la imagen aquí
Obtenga la grabación de la cámara y guarde el video

import cv2

video = cv2.VideoCapture(0)
while(True):
    # 获取一帧
    _, frame = video.read()
    # 将这帧转换为灰度图
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    cv2.imshow('frame', gray)
    if cv2.waitKey(1) == ord('q'):
        break

video.release()

Luego, generará continuamente cada fotograma que reciba la cámara, porque lo que se lee es escala de grises, aquí también hay escala de grises, puede dejar que salga normalmente sin modificaciones, es decir, comente la declaración de conversión de cvtColor, por cierto, cambie el immuestre el objeto de salida al marco original (el marco de lectura), y puede obtener el mapa de colores.
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
Haz un pequeño cambio para que guarde el video:

import cv2

video = cv2.VideoCapture(0)

# 定义编码方式并创建VideoWriter对象
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
outfile = cv2.VideoWriter('res.mp4', fourcc, 25., (640, 480))

while(video.isOpened()):
    flag, frame = video.read()

    if flag:
        outfile.write(frame)  # 写入文件
        cv2.imshow('frame', frame)
        if cv2.waitKey(1) == ord('q'):
            break
    else:
        break

video.release()

como sigue:
inserte la descripción de la imagen aquí

2. Base de la imagen

La imagen en la computadora se compone de pequeños cuadrados de colores, que son las unidades básicas de procesamiento llamadas píxeles. Su tamaño depende de la resolución de la computadora, cuanto mayor sea la resolución, más pequeños serán los píxeles. Se usa una imagen binaria simple, cuyos valores de píxel son solo 0 y 1, para identificar dos colores de blanco y negro; la imagen en escala de grises adicional aquí es para refinar el blanco y negro para que la imagen sea mucho más vívida, es decir, para representar El valor de blanco y negro se almacena de 0 a 255, 0 es negro puro, 1 es blanco puro, y el degradado de blanco y negro en el medio es más delicado; además, es una imagen en color y la composición del color se compone básicamente de tres colores primarios en diferentes proporciones, y la imagen en color tiene tres valores para representar los valores de los tres colores primarios, es decir, el píxel de una imagen en color, su El color se compone de tres valores, este modo también se denomina espacio de color RGB. Por ejemplo, [0, 0, 0] representa negro puro, [255, 255, 255] representa blanco puro y [255, 0, 0], [0, 255, 0] y [0, 0, 255] representan rojo respectivamente Los tres colores primarios de verde y azul, por lo que el espacio de color RGB también se denomina tres canales.En opencv, el orden de los tres canales es el orden inverso de BGR. Una imagen en color se compone de una matriz compuesta por tres canales, por lo que a menudo se presenta Numpy para cooperar al procesar imágenes en color. El procesamiento de imágenes también es una cuestión de matemáticas.


Ejemplo sencillo:

import cv2
import numpy as np

# 黑白图
b = np.zeros((100, 100), dtype=np.uint8)
w = np.zeors((100, 100), dtype=np.uint8)
w[:100, :100] = 255
print(b, w, sep="\n\n")

cv2.imshow("black", b)
cv2.imgshow("white", w)
cv2.waitKey()

# 三个三原色图片
r = np.zeros((300, 300, 3),dtype=np.uint8)
g = np.zeros((300, 300, 3),dtype=np.uint8)
b = np.zeros((300, 300, 3),dtype=np.uint8)
r[:,:, 2] = 255
g[:,:, 1] = 255
b[:,:, 0] = 255

cv2.imshow("red", r)
cv2.imshow("green", g)
cv2.imshow("blue", b)
cv2.waitKey()

# 包含三原色的图片
img = np.zeros((300, 300, 3), dtype=np.uint8)
img[:, 0:100, 2] = 255
img[:, 100:200, 1] = 255
img[:, 200:300, 0] = 255
cv2.imshow("RGB", img)

# 红橙黄绿蓝靛紫
img = np.zeros((300, 700, 3), dtype=np.uint8)
# 红
img[:,0:100,2] = 255
# 橙
img[:,100:200,2] = 255
img[:,100:200,1] = 97
# 黄
img[:,200:300,1] = 255
img[:,200:300,2] = 255
# 绿
img[:,300:400,1] = 255
# 蓝
img[:,400:500,0] = 255
# 靛
img[:,500:600,0] = 84
img[:,500:600,1] = 46
img[:,500:600,2] = 8
# 紫
img[:,600:700,0] = 240
img[:,600:700,1] = 32
img[:,600:700,2] = 160
# 输出
cv2.imshow("seven", img)
cv2.waitKey()

La salida no aparece, eso es todo. De hecho, si desea crear una tabla de comparación de colores, también puede iterar un canal por un canal, y luego iterar la secuencia completa y generarla, de modo que haya una tabla de colores, pero aún necesita referirse a la real nombre si desea prepararse para el valor.

gráfico aleatorio

Toda la imagen aleatoria en escala de grises es el estado sin señal de TV en el pasado.

import cv2
import numpy as np

img = np.random.randint(0, 256, size=[300, 300], dtype=np.uint8)
cv2.imshow("老花", img)
cv2.waitKey()

img = np.random.randint(0, 256, size=[300, 300], dtype=np.uint8)
cv2.imshow("彩色老花", img)
cv2.waitKey()

inserte la descripción de la imagen aquí| inserte la descripción de la imagen aquí
Se ha descrito anteriormente que el mapa de color RGB tiene tres canales, y opencv proporciona la implementación de la división de canales

import cv2
import numpy as np

img = cv2.imread(r"D:\img\among.png")
# b, g, r = cv2.split(img) 等同
cv2.imshow("0", img[:,:,0])
cv2.imshow("1", img[:,:,1])
cv2.imshow("2", img[:,:,2])

# 同样的拆分功能
b, g, r = cv2.split(img)
# 合并成原图
img_mer = cv2.merge([b, g, r])
cv2.waitKey()

Efecto:
inserte la descripción de la imagen aquí

tres valores de atributo

  • forma, img.shape, indica la longitud, el ancho y la profundidad de la secuencia img,
  • size , img.size, indica el número de píxeles, fila x columna x canal
  • dtype, tipo de datos de imagen

3. Espacio de color y conversión

El espacio de color, el modo de expresar el color, el espacio de color común es el espacio de color RGB, pero en opencv es el canal BGR inverso. Además, hay GRIS, que es una imagen en escala de grises de ocho bits, el espacio de color XYZ, el espacio de color YCrCb, el espacio de color HSV, el espacio de color HLS y el espacio de color Bayer. . . . . . De acuerdo con el espacio de color de las diferentes necesidades, también se puede convertir cuando sea necesario.Aquí está para aprender sobre sus características y conversión mutua.

espacio de color gris

Imagen en escala de grises de 8 bits, correspondiente al rango de valores binarios de 8 bits es 0-255, lo que significa 256 niveles de gris, 0 significa negro puro, 255 significa blanco puro y el valor medio es el gradiente de negro puro a blanco puro , por lo que es gris Gastar. En opencv, el espacio de color RGB se transforma en un espacio de color en escala de grises como GRIS, y su fórmula de transformación es la siguiente:

Rayo gris = 0,299 ∗ R + 0,587 ∗ G + 0,114 ∗ B Gris = 0,299*R+0,587*G+0,114*Bgris _ _ _=0.299R+0.587GRAMO+0.114B

Es relativamente sencillo convertir la escala de grises de Gray a un espacio de color RGB. El valor de RGB de tres canales es directamente el valor de Gray, es decir,
$$R = Gray\G = Gray\B = Gray\$$

En cuanto a la conversión entre GREY y BGR, de hecho, se puede realizar cuando opencv lo lee. No tengo idea de la aplicación por el momento. Aquí es principalmente para jugar con un ejemplo.

>>> import cv2
>>> import numpy as np
>>>
>>>
>>> mong = cv2.imread("among.png")
>>> gray = cv2.cvtColor(mong, cv2.COLOR_BGR2GRAY)
>>> cv2.imshow("source", mong)
>>> cv2.imshow("gray", gray)
>>> bgr_img = cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR)
>>> cv2.imshow("change again", bgr_img)
>>> cv2.waitKey()
-1
>>>
>>>
>>> img = np.random.randint(0, 256, size=[2,3], dtype=np.uint8)
>>> res = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
>>> res_change = cv2.cvtColor(res, cv2.COLOR_BGR2GRAY)
>>> img
array([[ 48,  27, 228],
       [ 94, 144, 234]], dtype=uint8)
>>> res
array([[[ 48,  48,  48],
        [ 27,  27,  27],
        [228, 228, 228]],

       [[ 94,  94,  94],
        [144, 144, 144],
        [234, 234, 234]]], dtype=uint8)
>>> res_change
array([[ 48,  27, 228],
       [ 94, 144, 234]], dtype=uint8)
>>>

Reproducido, no volvió a cambiar al color original.
inserte la descripción de la imagen aquí

espacio de color YCrCb

Para el sistema visual humano, debido a que la percepción del color de las personas es más baja que la percepción del brillo de la luz, y el espacio de color RGB se enfoca en el color, falta el indicador de brillo, por lo que hay un espacio de color YCrCb. En este espacio de color, Y representa el brillo de la fuente de luz, Cr representa el componente rojo y Cb representa el componente azul. La fórmula de conversión para convertir RGB a YCrCb es:
Y = 0.299 ∗ R + 0.587 ∗ G + 0.114 ∗ BC r = ( R − Y ) × 0.713 + delta C b = ( B − Y ) × 0.564 + delta Y = 0.299* R + 0.587*G + 0.114*B \\ Cr = (RY)\times0.713+delta\\Cb=(BY)\times0.564+deltaY=0.299R+0.587GRAMO+0.114BCr _=( RY )×0.713+delta _ _ _cb _=( BY )×0.564+El valor delta de d e lt a
tiene diferentes valores correspondientes a diferentes imágenes digitales:

valor delta Dígitos de la imagen
128 8 bits
32768 16 bits
0.5 imagen de precisión única
A su vez, la fórmula para convertir de YCrCb a RGB es:

R = Y + 1,403 ⋅ ( C r − delta ) G = Y − 0,714 ⋅ ( cr − delta ) − 0,344 ⋅ ( C segundo − delta ) segundo = Y + 1,773 ⋅ ( C segundo − delta ) R=Y+1,403\ cdot(Cr-delta)\\G=Y-0.714\cdot(cr-delta)-0.344\cdot(Cb-delta)\\B=Y+1.773\cdot(Cb-delta)R=Y+1.403( C rd e l a )GRAMO=Y0.714( crd e l a )0.344( C segundod e l a )B=Y+1.773( C segundod e l a )

También se llama YUV, Y representa brillo, U y V representan croma, y ​​es mejor que HSV en la detección del color de la piel.

espacio de color HSV

Se dice que es un modelo de color para la percepción visual. En este espacio de color, hay tres elementos: tono, saturación y brillo. El tono es el color de la luz, la saturación es la profundidad del color y el brillo es el brillo de luz percibida por el ojo humano.

  • Hue H, los seis colores rojo, amarillo, verde, azul y rojo corresponden a un círculo de 360 ​​grados (es por eso que a las personas que crean estos conceptos les gusta hacer desconcertantes a las personas);
  • La saturación S, una relación, es decir, un decimal, varía de 0 a 1, lo que indica la relación de la pureza máxima del color al color, la saturación es 0 es gris y el máximo es 1 es el color en sí;
  • Brillo V, el brillo del color, también tiene un rango de valores de [0, 1].

La fórmula para convertir RGB a HSV es la siguiente:
V = brillo máximo ( R , G , B ): S = { V − min ( R , G , B ) , V ≠ 0 0 , otros tonos: H = { 60 ( GRAMO - segundo ) v - min ( R , GRAMO , segundo ) , V = R 120 + 60 ( segundo - GRAMO ) V - min ( R , GRAMO , segundo ) , V = GRAMO 240 + 60 ( R - G ) V - min ( R , G , B ) , V = B Matiz: H = { H + 360 , H < 0 H , otro V = max(R, G, B)\\brightness: S= \begin{cases} V- min(R , G, B), &V\ne0\\ 0,& other \end{cases}\\hue: H= \begin{cases} \cfrac{60(GB)}{v-min(R, G , B) },&V=R\\ 120+\cfrac{60(BG)}{V-min(R, G, B)}, &V=G\\ 240+\cfrac{60(RG)}{V -min( R, G, B)}, &V=B \end{casos}\\Hue: H= \begin{casos} H+360,&H<0\\ H,&otros\end{casos}V=máx ( R , _G ,segundo )Brillo: S={ Vmin ( R ,G ,B ) ,0 ,V=0OtroTono: H= vmin ( R ,G ,segundo )60 ( Gb ),120+Vmin ( R ,G ,segundo )60 ( BG ),240+Vmin ( R ,G ,segundo )60 ( RG ),V=RV=GRAMOV=BTono: H={ H+360 ,H ,H<0Otro
Lo anterior es la fórmula para convertir RGB a HSV. Es realmente problemático. Conocer el principio también es conveniente para la depuración. De hecho, se puede hacer mediante las funciones internas de opencv. Solo necesita preocuparse por el significado de los tres elementos importantes anteriores.

>>> rgb_b = np.ones((2, 3, 3), dtype=np.uint8)
>>> rgb_g = np.ones((2, 3, 3), dtype=np.uint8)
>>> rgb_r = np.ones((2, 3, 3), dtype=np.uint8)
>>> rgb_b[:, :, 0], rgb_g[:, :, 1], rgb_r[:, :, 2] = 255, 255, 255
>>> hsv_b = cv2.cvtColor(rgb_b, cv2.COLOR_BGR2HSV)
>>> hsv_g = cv2.cvtColor(rgb_g, cv2.COLOR_BGR2HSV)
>>> hsv_r = cv2.cvtColor(rgb_r, cv2.COLOR_BGR2HSV)
>>> rgb_b
array([[[255,   1,   1],
        [255,   1,   1],
        [255,   1,   1]],

       [[255,   1,   1],
        [255,   1,   1],
        [255,   1,   1]]], dtype=uint8)
>>> hsv_b
array([[[120, 254, 255],
        [120, 254, 255],
        [120, 254, 255]],

       [[120, 254, 255],
        [120, 254, 255],
        [120, 254, 255]]], dtype=uint8)
>>> rgb_g
array([[[  1, 255,   1],
        [  1, 255,   1],
        [  1, 255,   1]],

       [[  1, 255,   1],
        [  1, 255,   1],
        [  1, 255,   1]]], dtype=uint8)
>>> hsv_g
array([[[ 60, 254, 255],
        [ 60, 254, 255],
        [ 60, 254, 255]],

       [[ 60, 254, 255],
        [ 60, 254, 255],
        [ 60, 254, 255]]], dtype=uint8)
>>> rgb_r
array([[[  1,   1, 255],
        [  1,   1, 255],
        [  1,   1, 255]],

       [[  1,   1, 255],
        [  1,   1, 255],
        [  1,   1, 255]]], dtype=uint8)
>>> hsv_r
array([[[  0, 254, 255],
        [  0, 254, 255],
        [  0, 254, 255]],

       [[  0, 254, 255],
        [  0, 254, 255],
        [  0, 254, 255]]], dtype=uint8)
>>>

espacio de color HLS

Es similar al espacio de color HSV, pero los tres elementos del espacio de color HLS son: tono H, brillo L y saturación S. Así es como se describe en el texto, ¿cuál es la diferencia? ¿Palabras que describen el brillo? Sin habla.

función de conversión de tipo

La conversión entre los diversos espacios de color anteriores y el espacio de color RGB se puede realizar en la función de conversión de tipo proporcionada por opencv.

dst = cv2.cvtColor(src, code[, dstCn])

Para conversiones de diferentes tipos, se pasan diferentes valores de parámetros de código, y dstCn es el número de canal de la imagen de destino, que es 0 de forma predeterminada, y luego el número de canal se determinará automáticamente por la imagen y el código originales.

valor del código analizar
cv2.COLOR_BGR2RGB Convierta el tipo BGR al tipo RGB en opencv
cv2.COLOR_RGB2BGR Convierta el tipo RGB al tipo BGR en opencv
cv2.COLOR_BGR2GRAY BGR a GRIS
cv2.COLOR_GRAY2BGR GRIS a BGR
cv2.COLOR_BGR2XYZ BGR a XYZ
cv2.COLOR_XYZ2BGR XYZ a BGR
cv2.COLOR_BGR2YCrCb BGR a YCrCb
cv2.COLOR_YCrCb2BGR YCrCb a BGR
cv2.COLOR_BGR2HSV BGR a HSV
cv2.COLOR_HSV2BGR HSV a BGR
cv2.COLOR_BGR2HLS BGR a HLS
cv2.COLOR_BayerBG2BGR Anti-mosaico, también modo BG de Bayer

En los parámetros anteriores, hay una conversión entre RGB y BGR. En opencv, el orden de los canales es generalmente BGR, que se invierte. ¿Qué pasa con la conversión de RGB? De acuerdo con los resultados de la operación práctica, los valores de los canales B y R se reemplazarán entre sí, es decir, los dos canales se cambiarán, pero la imagen de representación de opencv todavía está en el mismo orden de canales, por lo que si se muestra la imagen, el color cambiará.

>>> import cv2
>>> import numpy as np
>>>
>>>
>>> img = np.random.randint(0, 256, size=(2, 3, 3), dtype=np.uint8)
>>> rgb_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
>>> img
array([[[ 69, 184,  11],
        [193,   4, 194],
        [239, 139, 146]],

       [[188,  30,  44],
        [ 60, 145, 133],
        [ 46, 181, 139]]], dtype=uint8)
>>> rgb_img
array([[[ 11, 184,  69],
        [194,   4, 193],
        [146, 139, 239]],

       [[ 44,  30, 188],
        [133, 145,  60],
        [139, 181,  46]]], dtype=uint8)
>>> mong = cv2.imread("among.png")
>>> rgb_mong = cv2.cvtColor(mong, cv2.COLOR_BGR2RGB)
>>> cv2.imshow("source", mong)
>>> cv2.imshow("rgb_res", rgb_mong)
>>> cv2.waitKey()
-1

A partir de los cambios en la matriz anterior y las imágenes a continuación, podemos ver claramente los cambios internos y los cambios de macro. Incluso si se reemplazan los dos canales, el orden de los canales de la imagen predeterminada de opencv no debería cambiar, o las reglas internas de la función imshow Sigue siendo del orden de canales de bgr, lo que hace que el color de la imagen sea diferente.

inserte la descripción de la imagen aquí

Extraer un color específico

Para un bloque de color específico en la imagen, cuando lo necesitemos, podemos iterar la imagen y producir una imagen que solo contenga el bloque de color. Por ejemplo, la división de color de Doraemon anterior es muy obvia, lo cual es muy adecuado para este intento. . Además, la realización de esta idea depende de la función inRange de opencv.

dst = cv2.inRange(src, lowerb, upperb)

La función anterior es extraer el color del área [inferiorb, superiorb] en la imagen, pero debe tenerse en cuenta que si es una imagen en escala de grises, inferiorb es solo un valor entero, pero si es una imagen en el espacio de color RGB , lowerb necesita una matriz para describir el color, y upperb es lo mismo que arriba. Bueno, pero la característica específica del hardware de expresar el color con tres canales es realmente un dolor de cabeza para mí. En HSV, solo hay una forma de expresar el color, lo cual es muy atractivo para los usuarios. Está bien, intente esto.

>>> import cv2
>>> import numpy as np
>>>
>>> mong = cv2.imread("among.png")
>>> mong_hsv = cv2.cvtColor(mong, cv2.COLOR_BGR2HSV)
>>> bmin, bmax = np.array((100, 43, 46)), np.array((125, 255, 255))
>>> mask = cv2.inRange(mong_hsv, bmin, bmax)
>>> blue = cv2.bitwise_and(mong, mong, mask=mask)
>>> ymin, ymax = np.array((26, 43, 46)), np.array((34, 255, 255))
>>> ymask = cv2.inRange(mong_hsv, ymin, ymax)
>>> rmin, rmax = np.array((0, 43, 46)), np.array((10, 255, 255))
>>> rmask = cv2.inRange(mong_hsv, rmin, rmax)
>>> yellow = cv2.bitwise_and(mong, mong, mask=ymask)
>>> red = cv2.bitwise_and(mong, mong, mask=rmask)
>>> cv2.imshow("source", mong)
>>> cv2.imshow("blue", blue)
>>> cv2.imshow("yellow", yellow)
>>> cv2.imshow("red", red)
>>> cv2.waitKey()
-1

inserte la descripción de la imagen aquí
Lo anterior es un experimento basado en la tabla de comparación HSV buscada. Debería ser que los colores en la imagen no están completamente de acuerdo con la comparación de colores normal, por lo que lo que obtienes también son piezas rotas de bloques de color, lo cual es realmente agotador.
Sin embargo, la extracción de marcas de agua me dio ganancias inesperadas en esta parte.

>>> import cv2
>>> import numpy as np
>>>
>>>
>>> watermark = img[850:, 580:]
>>> wm_abstract = cv2.inRange(watermark, (230, 230, 230), (255, 255, 255))
>>> cv2.imshow("source", img)
>>> cv2.imshow("watermark_part", watermark)
>>> cv2.imshow("watermark", wm_abstract)
>>> cv2.waitKey()
-1
>>> 

De esta manera, incluso si se extrae la parte de la marca de agua, para este tipo de marca de agua de color puro, el inRange de RGB es más útil.
inserte la descripción de la imagen aquí

Marcado y detección del tono de piel

De acuerdo con el rango de color determinado anteriormente, marque el rango de color del color de la piel correspondiente a la foto humana, y luego puede obtener el área correspondiente y luego extraerla. El libro usa HSV para esto, pero hay información de que YCrCb es mejor para esta escena. Veo si puedes probar ambos.

En el libro, el tono y la saturación del color de la piel se establecen entre [5, 170] y [25, 166]. No estoy seguro si es para las imágenes de ejemplo en el libro, pero las usaré primero, aunque Utilizo otras imágenes para experimentos.

>>> import cv2
>>> import numpy as np
>>>
>>>
>>> img = cv2.imread("eason.png")
>>> hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
>>> h, s, v = cv2.split(hsv)
>>> hmask = cv2.inRange(h, 5, 170)
>>> smask = cv2.inRange(s, 25, 166)
>>> mask = hmask & smask
>>> roi = cv2.bitwise_and(img, img, mask=mask)
>>> cv2.imshow("source", img)
>>> cv2.imshow("skin", roi)
>>> cv2.waitKey()
-1

inserte la descripción de la imagen aquí
En cuanto a los resultados, la detección del color de la piel aún es posible. A continuación, intente la detección de YCrCb. Del efecto anterior, de hecho, la parte del borde no se procesa bien, por lo que el filtro de paso alto, una de las cuatro técnicas de desenfoque de opencv, se usa a continuación.

# 引入部分和上面的一致
>>> ycrcb = cv2.cvtColor(img, cv2.COLOR_BGR2YCrCb)
>>> y, cr, cb = cv2.split(ycrcb)
>>> cr = cv2.GaussianBlur(cr, (5, 5), 0)
>>> _, skin = cv2.threshold(cr, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
>>> cv2.imshow("res", skin)
>>> cv2.imshow("source", img)
>>> cv2.waitKey()
-1

inserte la descripción de la imagen aquí
El efecto es bastante bueno, pero solo puedo copiar el ejemplo y no puedo obtener una imagen en color.

canal alfa

Sobre la base del espacio de color RGB, se agrega el canal A para indicar transparencia u opacidad.Este es el espacio de color RGBA. El rango de valores del canal A puede ser [0, 1] o [0, 255]. En el procesamiento de imágenes común, generalmente hay tres canales RGB, por lo que para usar el espacio de color RGBA, se requiere cvtColor para la conversión. Aquí es solo un registro, no una expansión.

4. Operación de imagen

Se dice, ah, se dice que la adición de imágenes y las operaciones de bits se utilizan para la descomposición del plano de bits de la imagen, el cifrado XOR de la imagen, la marca de agua digital, la codificación/descodificación de rostros, etc. Si desea invertir, no está claro por el momento. El procesamiento de esta parte se demuestra temporalmente mediante la programación interactiva de Python.

Suma

Hay dos tipos principales, uno es la suma liderada por el operador simple +, y el otro es la función de suma proporcionada por opencv. Describa las reglas:

  • Operador más, cuando la imagen a y la imagen b usan el operador más simple para realizar la operación más, una vez que sus resultados exceden el valor máximo de escala de grises de 255, el valor es módulo 256, y el valor de suma es este. Si no se excede el resto, será operado normalmente.
    a + segundo { a + segundo , a + segundo ≤ 255 mod ( a + segundo , 256 ) , a + segundo > 255 a+b \begin{casos} a+b,&a+b\le255\\ mod(a+ segundo , 256),&a+b>255 \end{casos}a+b{ a+b ,m o d ( un+b ,256 ) ,a+b255a+b>255
  • cv2.add(a, b), la imagen a y la imagen b se suman usando esta función, que es la misma que la suma dominada por el operador más anterior, y también hay dos resultados. El primero es cuando la suma de los dos es mayor a 255, entonces déjelo reservar como valor máximo, 255 es el valor de saturación, tope, si no es mayor a 255, se agregará normalmente.
    cv 2. sumar ( un , segundo ) { un + segundo , un + segundo ≤ 255 255 , un + segundo > 255 cv2 agregar(a, b) \begin{casos} a+b, &a+b\le255\\ 255, &a+b>255 \end{casos}c v 2. añadir ( un , _segundo ){ a+b ,255 ,a+b255a+b>255

Tomemos un ejemplo simple

import cv2
import numpy as np

# 灰度图模式读取
img = cv2.imread('among.png', 1)
# 加法处理
a = img + img
b = a + a
c = cv2.add(img, img)
c = cv2.add(c, c)

cv2.imshow("a", a)
cv2.imshow("b", b)
cv2.imshow("c", c)
cv2.imshow("d", d)
cv2.waitKey()

Los resultados de la operación son los siguientes:
inserte la descripción de la imagen aquí
a y b son operaciones de suma de imágenes usando el operador de suma, y ​​c y d son operaciones de suma usando la función suma de cv2.Se puede ver claramente que la primera tiene un sentido de línea en la más y más operaciones de suma Es más obvio que los de color se oscurecen cada vez más, mientras que los últimos son al revés, se saturan más y aparecen más y más blancos. Este es un procesamiento simple de imágenes, pero si es entre dos imágenes o incluso entre valores e imágenes, no está claro, porque no hay una referencia.

suma ponderada

La suma ponderada es para tener en cuenta los elementos del peso de la imagen al calcular la suma de los valores de píxel de las dos imágenes. Las dos imágenes de suma ponderada deben tener el mismo tamaño y tipo, pero no hay requisitos para el canal y el tipo específico. Sin embargo, la información del blog que encontré está básicamente escrita y no hay una declaración adecuada para referencia humana, mdzz. Por el momento, copiemos el concepto del libro aquí y usemos la fórmula:
dst = saturar ( src 1 × α + src 2 × β + γ ) dst = saturar (src1\times\alpha + src2\times\beta+ \gama)d s t=s a t u r a t e ( src 1×a+src2 _×b+γ )
La realización de esta suma ponderada es la función addWeighted en opencv. En correspondencia con la fórmula anterior, también necesita pasar cinco parámetros: src1, alpha, src2, beta, gama. El llamado peso es la diferencia entre el dos imágenes en mi opinión Proporción, que es más obvia en los resultados de la imagen final, por lo que lo anterior se puede entender como: imagen de resultado = imagen 1 x coeficiente 1 + imagen 2 x coeficiente 2 + cantidad de ajuste de brillo.

Ejemplo simple de combinación de imágenes:

import cv2
import numpy as np

a = cv2.imread('blena.png')
b = cv2.imread('bboat.png')
c = cv2.addWeighted(a, 0.2, b, 0,8, 0)
d = cv2.addWeighted(a, 0.5, b, 0,5, 0)
e = cv2.addWeighted(a, 0.8, b, 0,2, 0)
cv2.imshow("c", c)
cv2.imshow("d", d)
cv2.imshow("e", e)
cv2.waitKey()

Debido a que realmente no tengo ningún recurso, tuve que tomar capturas de pantalla de dos imágenes en los libros de Baidu y guardarlas para experimentar, y luego mostrarlas de acuerdo con la proporción creciente de la imagen de la cara. Los resultados son los siguientes: Los resultados son obvio
inserte la descripción de la imagen aquí
. La proporción es cada vez más grande, y la cara de la imagen es cada vez más obvia. Este es un ejemplo de imágenes mixtas. Escuché que si las imágenes son de diferentes tamaños, puede usar el cambio de tamaño para ajustarlas. Intentar otra vez. Después de cambiar la imagen, el código se ajusta a:

import cv2
import numpy as np

a = cv2.imread("ayanamirei.jpg")
b = cv2.imread("asikaj.jpg")

# 比例调整大小,本来size并不一样,但调整后以外发现一致了,应该是算法问题
a = cv2.resize(a, None, fx=0.1, fy=0.1, interpolation=cv2.INTER_LINEAR)
b = cv2.resize(b, None, fx=0.1, fy=0.1, interpolation=cv2.INTER_LINEAR)

c = cv2.addWeighted(a, 0.2, b, 0.8, 0)
d = cv2.addWeighted(a, 0.5, b, 0.5, 0)
e = cv2.addWeighted(a, 0.8, b, 0.2, 0)
cv2.imshow("c", c)
cv2.imshow("d", d)
cv2.imshow("e", e)
cv2.waitKey()

Los ajustes funcionaron bien y luego pude volver a realizar el procesamiento de imágenes combinadas. El mapa de color obtenido es el siguiente:
inserte la descripción de la imagen aquí
Relativamente hablando, la proporción de 0,4 y 0,3 debería ser mejor Cuando el fondo no es tan obvio, debería ser mejor despejar el fondo. La elección del último parámetro de cambio de tamaño tiene una gran influencia en el dibujo:

  • INTER_NEAREST: interpolación del vecino más cercano
  • INTER_LINEAR: interpolación lineal (predeterminado)
  • INTER_AREA: interpolación de área
  • INTER_CUBIC: interpolación spline cúbica
  • INTER_LANCZOS4: Se recomienda la interpolación de Lanczos
    cv2.INTER_AREA para alejar, cv2.INTER_CUBIC y cv2.INTER_LINEAR para acercar

operación lógica bit a bit

En cuanto a las operaciones lógicas, existen operaciones como AND o NOT, XOR, etc. La operación lógica bit a bit aquí es convertir un número en un número binario y realizar operaciones lógicas en cada número de bit correspondiente. No es necesario ampliar las operaciones lógicas específicas, y no se registrarán. Las funciones de operación lógica bit a bit proporcionadas por opencv son:

  • Bitwise y, dst = cv2.bitwise_and(src1, src2[, mask])
  • Bitwise o, dst = cv2.bitwise_or(src1, src2[, mask])
  • Bitwise no, dst = cv2.bitwise_not(src[, mask])
  • Bitwise XOR, dst = cv2.bitwise_xor(src1, src2[, mask])
    máscara, máscara de operación opcional, valor de matriz de un solo canal de 8 bits

Uso de operaciones AND bit a bit

Para operaciones AND bit a bit, cuando se procesan imágenes en escala de grises, el píxel es AND bit a bit con el valor 0, y solo se obtiene 0, y el AND bit a bit con 255 es el valor original. Cuando una imagen con una gran cantidad de valores 0 y 255 valores En lugar de AND bit a bit, lo que obtiene es una imagen parcialmente "ennegrecida", como si estuviera recortada. Para decirlo sin rodeos, se usa otra imagen para cubrir parcial o incluso completamente la imagen de destino.

import cv2
import numpy as np

img = cv2.imread("blena.png")
# 制作一个和原图同尺寸的数组
mask = np.zeros(img.shape, dtype=np.uint8)

# 固定区域设置纯白
mask[100:280, 100:250] = 255
a = cv2.bitwise_and(img, mask)

# 三图进行显示
cv2.imshow("source", img)
cv2.imshow("mask", mask)
cv2.imshow("res", a)
cv2.waitKey()

inserte la descripción de la imagen aquí

Bueno, excepto por la aplicación de operaciones AND bit a bit, los otros dos o tres parecen no tener aplicaciones por el momento. Sin embargo, debe tenerse en cuenta que las dos matrices para operaciones lógicas bit a bit deben ser del mismo tamaño, de lo contrario se producirán errores. Entonces, hay muchos usos que ajustarán el tamaño de la imagen.

Descomposición de planos de bits

La imagen en color se puede dividir en tres matrices de acuerdo con los tres canales RGB, que es el desmontaje de los canales; la imagen obtenida al combinar los píxeles en el mismo bit de la imagen también se denomina plano de bits, y este proceso se denomina una descomposición en plano de bits. En la imagen en escala de grises, el valor de un píxel va de 0 a 255, que es un rango de 8 bits en un byte, el valor de cada bit se extrae para obtener un plano de bits, más la imagen original, habrá un total de 9 imágenes. Si la imagen en color se divide en planos de bits, sería demasiado. Entonces, el ejemplo aquí es solo una imagen en escala de grises, que es más fácil de hacer.

Para una imagen en escala de grises, cuando se expande a un número binario y se corta el plano de bits, cuanto mayor sea el peso del bit donde se encuentra el plano de bits, mayor será la correlación entre el plano de bits y la imagen original. el peso del bit donde se encuentra el plano de bits Cuanto menor sea el correspondiente, menor será la correlación con la imagen original. Para decirlo sin rodeos, el plano de bits cortado por los dígitos correspondientes a la potencia 2 a la 0 es menos visible de la imagen original, y el plano de bits cortado por los dígitos correspondientes a la potencia 2 a la 7 es más similar a la imagen original

Para las imágenes en color RGB, se divide en tres canales, y el color correspondiente a los tres canales también es un número binario de 8 bits. Divídalos en tres canales y luego sincronice los dígitos correspondientes para cortar un plano de bits basado en el canal. y luego combinarlos, que es el plano de bits de la imagen original. Bueno, parece que la segmentación del plano de bits del mapa de color no es demasiado difícil.

Pasos de segmentación del plano de bits:

  • Extraiga el ancho y el alto de la imagen original y construya una matriz del mismo tamaño;
  • Construya la matriz anterior en un píxel cuyo valor sea 2 n 2^n2La matriz de n se usa para la extracción;
  • Realice una operación AND bit a bit en la matriz extraída y la imagen original para obtener el plano de bits
  • Para evitar que los planos de bits correspondientes a dígitos más pequeños se muestren como negro puro, es necesario establecer un umbral, de modo que el resultado final sea solo valores en blanco y negro, como 0 y 255, o sea verdadero o falso. .
import cv2
import numpy as np

img = cv2.imread("alian.jpg", 0)
img = cv2.resize(img, None, fx=0.4, fy=0.4, interpolation=cv2.INTER_LINEAR)
cv2.imshow("source", img)
w, h = img.shape
# 创建8层同规模的矩阵,每个矩阵用来放置对应数位的提取矩阵,在后面的循环中给对应矩阵赋值
arrays = np.zeros((w, h, 8), dtype=np.uint8)
for i in range(8):
    x[:, :, i] = 2**i

# 循环对原图进行按位与运算提取位平面,然后进行阈值处理,最后输出图像
for i in range(8):
    temp = cv2.bitwise_and(img, x[:, :, i])
    # 将temp中大于0的值转为True,除此以外的值转换为False
    mask = temp>0
    # 将temp中True换成255
    temp[mask] = 255
    cv2.imshow("res"+str(i+1), temp)
cv2.waitKey()

inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
De lo anterior, se puede ver claramente que la extracción del plano de bits y la visualización de una imagen en escala de grises (se usa el avatar de Alian, desafortunadamente es demasiado blanco y el cuerpo es demasiado grande, por lo que es necesario modificar el tamaño), en este Si desea procesar la imagen en color, agregue la imagen en color en el proceso anterior para dividir los tres canales y finalmente sintetizar los tres canales. como sigue:

import cv2
import numpy as np

img = cv2.imread("alian.jpg")
img = cv2.resize(img, None, fx=0.4, fy=0.4, interpolation=cv2.INTER_LINEAR)
cv2.imshow("source", img)
w, h = img.shape[:2]
b, g, r = cv2.split(img)
b_arr = np.zeros((w, h, 8), dtype=np.uint8)
g_arr = np.zeros((w, h, 8), dtype=np.uint8)
r_arr = np.zeros((w, h, 8), dtype=np.uint8)
for i in range(8):
    b_arr[:, :, i], g_arr[:, :, i], r_arr[:, :, i] = 2**i, 2**i, 2**i

for i in range(8):
    t1 = cv2.bitwise_and(b, b_arr[:, :, i])
    t2 = cv2.bitwise_and(g, g_arr[:, :, i])
    t3 = cv2.bitwise_and(r, r_arr[:, :, i])
    mask1 = t1 >0
    mask2 = t2 >0
    mask3 = t3 >0
    t1[mask1], t2[mask2], t3[mask3] = 255, 255, 255
    temp = cv2.merge([t1, t2, t3])
    cv2.imshow("res"+str(i+1), temp)
cv2.waitKey()

inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

filigrana

Todos los sitios web importantes están muy preocupados por sus propios problemas de derechos de autor, y no pueden esperar para ponerles varios sellos. La marca de agua en la imagen es una manifestación. A veces, la carga y, cuando se muestra en el sitio web, habrá ser huellas de otras personas, lo cual es muy asqueroso. . Sin embargo, para los particulares, esto también forma parte de los derechos de propiedad intelectual a proteger, y es una cuestión de opinión pública.

Anteriormente se introdujo que un plano de bits es una colección de píxeles de una imagen basada en los dígitos del mismo binario. Cuanto más grande es el dígito, más se acerca la imagen del plano de bits correspondiente a la imagen original, y cuanto más pequeño es el dígito, mayor la diferencia con la imagen original. Por lo tanto, el bit más bajo en el número binario es la posición 0 de 2, también llamado bit menos significativo (LSB, Least Significant Bit) . Cuando la información se almacena en este bit y se combina en la imagen original, esta información se oculta. Información, marca de agua pertenece a este tipo de información oculta. ¿Cómo?

La primera es leer la imagen que necesita una marca de agua y una imagen con una marca de agua clara, extraer el bit menos significativo correspondiente al plano de bits de esta última y luego hacer los ajustes apropiados de acercamiento o alejamiento de acuerdo con el tamaño de la imagen, y luego péguelo en la imagen que necesita una marca de agua, este paso puede usar la función de suma ponderada de cv2 o la función de pegar de PIL.

Mapa de marca de agua hecho a sí mismo

En primer lugar, como no tengo la imagen original de la marca de agua, quiero generar dos imágenes originales de la marca de agua con mi propia etiqueta, una con texto blanco sobre fondo negro y dos con texto negro sobre fondo blanco. Es muy sencillo generar imágenes de fondo en blanco y negro. Un valor de píxel de 0 es negro puro y un valor de píxel de 255 es blanco puro. En cuanto a agregar texto, puede usar la función putText que viene con cv2. Vamos, empieza a construir.

import cv2
import numpy as np

# 制造黑色和白色背景
black_w = np.zeros((300, 450), dtype=np.uint8)
white_b = np.ones((300, 450), dtype=np.uint8)*255

# 调用putText函数添加手写体的标签,距离左上角150的位置,字体大小为3,粗细为3
cv2.putText(black_w, 'JackSAMA', (0, 150), cv2.FONT_HERSHEY_SCRIPT_SIMPLEX, 3, 255, 2)
cv2.putText(white_b, 'JackSAMA', (0, 150), cv2.FONT_HERSHEY_SCRIPT_SIMPLEX, 3, 0, 2)

cv2.imshow("black", black_w)
cv2.imshow("white", white_b)
cv2.waitKey()

inserte la descripción de la imagen aquí
La imagen de marca de agua está lista. De hecho, se puede generar de acuerdo con la situación real. Siempre que la función de marca de agua esté personalizada, también se puede ajustar de acuerdo con el tamaño de la imagen. Por supuesto, también se puede ajustar sincrónicamente. si hay una imagen real. Los parámetros de función de putText son principalmente los siguientes:

img = cv2.putText(img, text, org, fontFace, fontScale, color[, thickness[, lineType[, bottomLeftOrigin]]])
img, 操作图像对象
text,添加的文本,一般都是英文,中文使用会乱码,暂时也还没解决
fontFace,用过标签语言的应该都知道这是字体类型的意思
fontScale,字体大小
color,对于灰度图,简单的0-255表示即可,如果是rgb彩图就要适用(b, g, r)进行表示
thickness,线条粗细,默认是1
lineType,线条类型,默认是8连接类型
bottomLeftOrigin,默认为False,这样文本就是横着来;输入为True就是文本竖着来
Perfil delantero analizar
cv2.FONT_HERSHEY_SIMPLEX Las fuentes sans-serif normales son fuentes inglesas de uso común
cv2.FONT_HERSHEY_PLAIN fuente sans-serif pequeña
cv2.FONT_HERSHEY_DUPLEX tamaño normal sans-serif
cv2.FONT_HERSHEY_COMPLEX fuente serif normal
cv2.FONT_HERSHEY_TRIPLEX Fuentes serif de tamaño normal
cv2.FONT_HERSHEY_COMPLEX_SMALL versión simplificada serif
cv2.FONT_HERSHEY_SCRIPT_SIMPLEX fuente de estilo de escritura a mano
cv2.FONT_HERSHEY_SCRIPT_COMPLEX Versión compleja de fuente manuscrita
cv2.FONT_ITALIC marca en cursiva
tipo de línea analizar
cv2.LLENADO tipo lleno
cv2.LINE_4 4 tipo de conexión
cv2.LINE_8 8 tipo de conexión
cv2.LINE_AA Anti-aliasing para líneas más suaves

Las anteriores son algunas interpretaciones de los parámetros de fuente y tipos de línea en opencv Escuché que se puede reemplazar con una biblioteca de diseño propio, pero no sé cómo. Pero parece que agregar un parámetro de línea anti-aliasing parece mucho más cómodo.

Marca de agua incrustada
Agregue una marca de agua a la imagen de Doraemon.

>>> import cv2
>>> import numpy as np
>>>
>>> mong = cv2.imread("among.png")
>>> mong.shape
(347, 272, 3)
>>> watermark = cv2.imread("white_black_sign.png")
>>> watermark.shape
(300, 450, 3)
# 调整水印原图大小和对应待处理图片补充空白
>>> watermark = cv2.resize(watermark, None, fx=0.3, fy=0.3, interpolation=cv2.INTER_AREA)
>>> cv2.imshow("", watermark)
>>> cv2.waitKey()
-1
>>> watermark.shape
(90, 135, 3)
>>> temp = np.ones(mong.shape, dtype=np.uint8)*255
>>> temp[210:300, 137:272] = watermark
>>> cv2.imshow("", temp)
>>> cv2.waitKey()
-1
# 进行加权和拼接,实现图片添加水印
>>> res1 = cv2.addWeighted(mong, 0.9, temp, 0.1, 0)
>>> cv2.imshow("", res1)
>>> cv2.waitKey()
-1

inserte la descripción de la imagen aquí

quitar marca de agua

Muchas formas de eliminar la marca de agua son pedirle al artista que cree una imagen de marca de agua de color sólido como la que generé arriba, y luego identificar la gama de colores y luego fusionar las dos imágenes, es decir, pegarla, por lo que hay muchos usos. Uso de la biblioteca PIL

import cv2
import PIL import Image
import numpy as np

img = cv2.imread("./iamfine.png")
h, w, _ = img.shape[0:3]
#切割,根据实际水印位置而定,[y0:y1, x0:x1]为下面裁剪用法,裁剪完后可以用上面的方法输出查看一下
cropped = img[int(h*0.9):h, int(w*0.75):w]
# 对图片进行阈值化处理,把由后面两个参数划定的RGB色彩空间范围外的色彩输出为0或者255,由图片底色确定这个范围
thresh = cv2.inRange(cropped, np.array([230, 230, 230]), np.array([250, 250, 250]))
#创建结构和尺寸的数据元素
kernel = np.ones((3, 3), np.uint8)
# 扩展待修复区域
watermask = cv2.dilate(thresh, kernel, iterations=10)
specular = cv2.inpaint(cropped, watermask, 5, flags=cv2.INPAINT_TELEA)
#保存去除水印的残图
cv2.imwrite("new.png", specular)

# 用PIL的paste函数把残图粘贴在原图上得到新图
i = Image.open("./img/iamfine.png")
i2 = Image.open("./img/new.png")
i2.paste(i, (int(w*0.75), int(h*0.9), w, h))
i2.save("final.png")

Comparación de las dos imágenes:
|
En realidad, puede usar el método de agregar una marca de agua arriba para invertirlo.

Generar imágenes de personajes

Una imagen se compone de píxeles, y las computadoras almacenan imágenes en binario, y los bits utilizados para almacenar píxeles son la profundidad de la imagen, que se almacena en 1 bit. La imagen es en blanco o negro, porque solo hay 0 y 1 opciones; use un byte (8 bits) para almacenar el valor de 0-255. El color tiene tres colores primarios: rojo, verde y azul. Estos tres colores se pueden superponer para representar otros colores, y el color de los píxeles de esta imagen está determinado por los tres colores de RGB, que generalmente se denominan tres canales. porque usan tres caracteres respectivamente. Las secciones representan respectivamente los valores individuales de los tres colores primarios, y cuando se apilan juntos, es el color del píxel, que generalmente es (0-255, 0-255, 0-255 ) en representación de píxeles.


La imagen de caracteres que queremos generar es en realidad para establecer un mapeo de píxeles a caracteres, porque el conjunto de caracteres también es muy grande, incluso el conjunto ASCII más básico es de 128 caracteres, pero no necesitamos usar tantos, podemos use algunos caracteres simples para crear un conjunto de caracteres y luego combínelo con la tabla de colores del píxel (porque las reglas de mapeo están personalizadas).


La verdad es esta, pero no entendí los ejemplos de otras personas, pero otro método me ha ganado mucho, es decir, primero convertir la imagen en una imagen en escala de grises, es decir, una imagen en blanco y negro, en este momento, será Ser fácil convertir píxeles en caracteres mucho.
El funcionamiento sencillo es el siguiente:

import cv2
import numpy as np

str = "#+-."
img = cv2.imread("among.png", 0)
# 此时就只有height和width两个值,没有depth
h, w = img.shape[0:2]
for_change = np.ndarray([h, w])
font = cv2.FONT_HERSHEY_SIMPLEX
for i in range(0, h, 5):
    for j in range(0, w, 5):
        t = str[round(3-img[i, j]/255*3)]
        cv2.putText(for_change, t, (j, i), font, 0.1, color=(255, 255, 255))
        
cv2.imshow("", for_change)
cv2.waitKey(0)
cv2.imwrite("asciiPic.png", for_change)


Bueno, al menos se da cuenta, pero hay un problema con esto, es decir, incluso el mapa base se reemplaza juntos, y luego es un poco llamativo.

generar video de personajes

Debido a que un video es una imagen cuadro por cuadro, generar una imagen de personaje es la mitad del camino para generar un video de personaje, y la lógica anterior se puede repetir para generar un video de personaje.

import cv2
import numpy as np


def pixel2char(pixel):
    char_list = "@#$%&erytuioplkszxcv=+---.     "
    index = int(pixel / 256 * len(char_list))
    return char_list[index]


def get_char_img(img, scale=4, font_size=5):
    # 调整图片大小
    h, w = img.shape
    re_im = cv2.resize(img, (w//scale, h//scale))
    # 创建一张图片用来填充字符
    char_img = np.ones((h//scale*font_size, w//scale*font_size), dtype=np.uint8)*255
    font = cv2.FONT_HERSHEY_SIMPLEX
    # 遍历图片像素
    for y in range(0, re_im.shape[0]):
        for x in range(0, re_im.shape[1]):
            char_pixel = pixel2char(re_im[y][x])
            cv2.putText(char_img, char_pixel, (x*font_size, y*font_size), font, 0.5, (0, 0, 0))
    return char_img


def generate(input_video, output_video):
    # 1、读取视频
    cap = cv2.VideoCapture(input_video)

    # 2、获取视频帧率
    fps = cap.get(cv2.CAP_PROP_FPS)

    # 读取第一帧,获取转换成字符后的图片的尺寸
    ret, frame = cap.read()
    char_img = get_char_img(cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY), 4)

    # 创建一个VideoWriter,用于保存视频
    fourcc = cv2.VideoWriter_fourcc(*'mp4v')
    writer = cv2.VideoWriter(output_video, fourcc, fps, (char_img.shape[1], char_img.shape[0]))
    while ret:
        # 读取视频的当前帧,如果没有则跳出循环
        ret, frame = cap.read()
        if not ret:
            break
        # 将当前帧转换成字符图
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        char_img = get_char_img(gray, 4)

        # 转换成BGR模式,便于写入视频
        char_img = cv2.cvtColor(char_img, cv2.COLOR_GRAY2BGR)
        writer.write(char_img)
    writer.release()


if __name__ == '__main__':
    generate('in.mp4', 'out.mp4')

Bueno, esta construcción. . . . . . ¡No lo soporto, la computadora comienza a echar humo antes de que termine la generación! ! ! ¡El Maestro Lu está fumando! ! ! Después de desconectarse, el video no tiene la mitad de la duración del video original, ¡pero el tamaño es varias veces mayor que el del video original! ! ! Vamos a optimizarlo más tarde, si no puedes ordeñar, no puedes ordeñar.

La imagen usada arriba

inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
También hay una pieza de Rei Ayanami, pero es demasiado grande para pasarla. Hagamos esto primero y grabémoslo después.También hay un video: Bueno, parece tan difícil conseguir este recurso.

Recientemente lancé un sitio web personal, y varios artículos están listos para ser recopilados allí.Si está interesado, puede consultarlo:

pequeña estación rota

Supongo que te gusta

Origin blog.csdn.net/weixin_44948269/article/details/128150084
Recomendado
Clasificación