Añadir ruido aleatorio a una imagen en Go

En este artículo, vamos a demostrar cómo añadir ruido a una imagen en Golang. Una imagen con ruido es la presencia de artefactos que no provienen de la imagen original. Se trata de un artefacto en la imagen que aparece como una estructura granulada que cubre la imagen. En el aprendizaje automático, se trata de la adición de valores de píxeles innecesarios que causan la pérdida de información y calidad de la imagen.

En este ejemplo, vamos a utilizar tantas bibliotecas Go por defecto como sea posible. Vamos a crear la superposición ruidosa y a fusionarla sobre la imagen original. La imagen resultante se llamará result.png. Para este proyecto de demostración, vamos a utilizar un archivo de imagen JPEG llamado image.jpg. Esta será la imagen original sobre la que añadiremos la superposición de ruido.

Para empezar con una pizarra limpia, comenzamos implementando un método para eliminar el archivo si existe.

func eliminarArchivo(archivo string) error {

	// eliminar el archivo si existe utilizando la función Remove()
	resultadoErrorDeEliminacion := os.Remove(fmt.Sprintf("%s/%s", trayectoria_del_projecto, archivo))
	if resultadoErrorDeEliminacion != nil {
		return resultadoErrorDeEliminacion
	}

	return nil
}

Para la recuperación de nuestra imagen original (es decir, jpeg) implementaremos el siguiente método:

func obtenerUnaImagenJpeg(nombreDeArchivo string) (image.Image, error) {

	archivoDeImagen, err := os.Open(fmt.Sprintf("%s/%s.jpg", trayectoria_del_projecto, nombreDeArchivo))
	if err != nil {
		return nil, errors.New(fmt.Sprintf("error al abrir el archivo original: %s", err))
	}

	imagenDecodificada, err := jpeg.Decode(archivoDeImagen)
	if err != nil {
		return nil, errors.New(fmt.Sprintf("no se ha podido decodificar la imagen original: %s", err))
	}

	defer func(archivo_de_imagen *os.File) {
		_ = archivo_de_imagen.Close()
	}(archivoDeImagen)

	return imagenDecodificada, nil
}

Para lograr la imagen ruidosa, vamos a implementar un método para crear una superposición ruidosa.

func crearSuperpuestoRuidoso(imagenDeFondo image.Image, opacidad int) (image.Image, error) {

	var opacidad_solicitada = uint8(0)
	if opacidad > 0 && opacidad < 256 {
		opacidad_solicitada = uint8(math.Round(float64(opacidad) * 2.56))
	}

	encuadernacionDeUnaImagen := imagenDeFondo.Bounds()
	anchuraDeImagen := encuadernacionDeUnaImagen.Dx()
	alturaDeImagen := encuadernacionDeUnaImagen.Dy()
	imagenSuperponer := image.NewRGBA(image.Rect(0, 0, anchuraDeImagen, alturaDeImagen))

	for pixel := 0; pixel < anchuraDeImagen*alturaDeImagen; pixel++ {
		desplazamientoDePixeles := 4 * pixel
		imagenSuperponer.Pix[0+desplazamientoDePixeles] = uint8(rand.Intn(256))
		imagenSuperponer.Pix[1+desplazamientoDePixeles] = uint8(rand.Intn(256))
		imagenSuperponer.Pix[2+desplazamientoDePixeles] = uint8(rand.Intn(256))
		imagenSuperponer.Pix[3+desplazamientoDePixeles] = opacidad_solicitada
	}

	archivoDelImagenConRuidoTemporal, png_err := os.Create(fmt.Sprintf("%s/%s", trayectoria_del_projecto, "imagen_ruidosa_temporal.png"))
	if png_err != nil {
		log.Fatal(png_err)
	}

	error_de_codification := png.Encode(archivoDelImagenConRuidoTemporal, imagenSuperponer)
	if error_de_codification != nil {
		return nil, error_de_codification
	}

	imagenRuidosaTemporal, err := os.Open(fmt.Sprintf("%s/%s", trayectoria_del_projecto, "imagen_ruidosa_temporal.png"))
	if err != nil {
		return nil, err
	}

	// Error de decodificación png
	resultado, errorDecodificacionPng := png.Decode(imagenRuidosaTemporal)
	if errorDecodificacionPng != nil {
		return nil, errorDecodificacionPng
	}

	defer func(imagen_rudiosa_temporal *os.File) {
		_ = imagen_rudiosa_temporal.Close()
	}(imagenRuidosaTemporal)

	// eliminar imagen_ruidosa_temporal.png con la función Remove()
	err = eliminarArchivo("imagen_ruidosa_temporal.png")
	if err != nil {
		return nil, err
	}

	return resultado, nil
}

Después de crear la imagen de superposición de ruido, tenemos que fusionarla sobre la imagen original. En el siguiente método, dibujaremos la superposición de ruido sobre la fuente original (en este caso la imagen original).

func fusionarYCrearUnaImagenConRuido(imagen_original image.Image, imagen_de_superposicion_de_ruido image.Image) error {

	compensacion := image.Pt(0, 0)
	limiteDeLaImagenOriginal := imagen_original.Bounds()
	imagenRuidosa := image.NewRGBA(limiteDeLaImagenOriginal)
	draw.Draw(imagenRuidosa, limiteDeLaImagenOriginal, imagen_original, image.Point{}, draw.Src)
	draw.Draw(imagenRuidosa, imagen_de_superposicion_de_ruido.Bounds().Add(compensacion), imagen_de_superposicion_de_ruido, image.Point{}, draw.Over)

	imagenResultante, err := os.Create(fmt.Sprintf("%s/%s", trayectoria_del_projecto, "resultado.png"))
	if err != nil {
		return errors.New(fmt.Sprintf("failed to create result image: %s", err))
	}

	errorDeCodificacionPng := png.Encode(imagenResultante, imagenRuidosa)
	if errorDeCodificacionPng != nil {
		return errorDeCodificacionPng
	}

	defer func(archivo_de_imagen *os.File) {
		_ = archivo_de_imagen.Close()
	}(imagenResultante)

	return nil
}

Por último, en la función principal, implementaremos todo el proceso recuperando nuestra imagen original en el proyecto. También puede modificar el proyecto basado en su preferencia personal para recuperar imágenes basadas en el argumento del comando por ejemplo.

func main() {

	err := eliminarArchivo("resultado.png")
	if err != nil {
		fmt.Println(err)
	}

	imagen_original, err := obtenerUnaImagenJpeg("imagen")

	if err != nil {
		log.Fatal(err)
	}

	// Imagen superpuesta con ruido
	imagenSuperpuestaConRuido, err := crearSuperpuestoRuidoso(imagen_original, 50)

	if err != nil {
		log.Fatal(err)
	}

	errorDeImagenResultante := fusionarYCrearUnaImagenConRuido(imagen_original, imagenSuperpuestaConRuido)

	if errorDeImagenResultante != nil {
		log.Fatal(errorDeImagenResultante)
	}
}

El resultado aparecerá como resultado.png localmente en el proyecto si todo ha ido bien.

Visite nuestro repositorio de GitHub para el código fuente del proyecto y clone nuestro repositorio para todos los proyectos.

Síguenos:

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *