Procesamiento y análisis de imágenes con OpenCV 4.10 en Java
Laboratorio académico de Sistemas Multiagente y Percepción Computacional
- Descripción del Proyecto
- Arquitectura del Sistema
- Rutinas Implementadas
- Resultados Visuales
- Fundamentos Teóricos
- Requisitos del Sistema
- Instalación y Configuración
- Ejecución del Proyecto
- Estructura del Proyecto
- Tecnologías Utilizadas
- Autor
Este repositorio contiene la implementación del Laboratorio No. 2 de la asignatura Sistemas Multiagente y Percepción Computacional del séptimo semestre de Ingeniería Informática. El proyecto explora el procesamiento digital de imágenes mediante la librería OpenCV 4.10.0 integrada con Java, utilizando NetBeans IDE como entorno de desarrollo y Apache Ant como sistema de construcción.
El trabajo está dividido en 4 rutinas independientes que cubren las operaciones más fundamentales en visión por computador: desde transformaciones básicas de espacio de color, pasando por algoritmos de detección de bordes basados en gradientes, hasta técnicas de detección de objetos en tiempo real mediante clasificadores en cascada Haar.
Cada rutina está diseñada como una clase ejecutable independiente (main propio), lo que permite su evaluación de forma modular y facilita la comprensión aislada de cada conjunto de técnicas.
flowchart TD
A[LaboratorioOpenCV.java - Verificacion] --> B[System.loadLibrary - opencv_java4100.dll]
B --> C[Rutina1Basico.java - Espacio Color + Umbral]
B --> D[Rutina2Bordes.java - Canny + Sobel]
B --> E[Rutina3Rostros.java - Haar Cascade + DNN]
B --> F[Rutina4Transformaciones.java - Resize - Rotate - Flip]
C & D & F --> G[Imagenes/foto1.png]
E --> H[Imagenes/foto2.jpg - Imagen con Personas]
C & D & E & F --> I[PNG Resultados - Salidas Procesadas]
Archivo: Rutina1Basico.java
Implementa el pipeline de procesamiento de imagen más fundamental en visión computacional: conversión de espacio de color, suavizado y segmentación por umbral.
foto1.png ──┬──► cvtColor(BGR→GRAY) ──────────────────► foto1_gris.png
│ │
│ └──► GaussianBlur(15×15, σ=0) ──► foto1_suavizada.png
│ │
│ └──► threshold(127, BINARY) ────► foto1_binaria.png
│
└──► [dimensiones en consola]
Operaciones implementadas:
| Operación | API OpenCV | Parámetros | Efecto |
|---|---|---|---|
| Conversión a grises | Imgproc.cvtColor() |
COLOR_BGR2GRAY |
Reduce 3 canales a 1 canal de intensidad |
| Filtro Gaussiano | Imgproc.GaussianBlur() |
Kernel 15×15, σ=0 | Eliminación de ruido de alta frecuencia |
| Umbralización binaria | Imgproc.threshold() |
umbral=127, maxVal=255 | Segmentación binaria global |
Por qué Gaussian Blur con kernel 15×15: Un kernel grande garantiza un suavizado agresivo que elimina artefactos de compresión y ruido; σ=0 hace que OpenCV calcule automáticamente la desviación estándar óptima a partir del tamaño del kernel.
Archivo: Rutina2Bordes.java
Implementa dos de los algoritmos más importantes en detección de bordes: el operador de Canny (óptimo según criterios de Canny, 1986) y el operador de Sobel (basado en gradiente discreto de primer orden).
foto1.png ──► cvtColor(BGR→GRAY) ──┬──► Canny(80, 200) ─────────────────────────► foto1_canny.png
│
├──► Sobel(CV_16S, dx=1, dy=0) ──► convertScaleAbs() ──┐
│ ├──► addWeighted(0.5, 0.5) ──► foto1_sobel.png
└──► Sobel(CV_16S, dx=0, dy=1) ──► convertScaleAbs() ──┘
Operaciones implementadas:
| Detector | API OpenCV | Parámetros | Descripción |
|---|---|---|---|
| Canny | Imgproc.Canny() |
low=80, high=200 | Detección óptima con supresión de no-máximos e histéresis |
| Sobel X | Imgproc.Sobel() |
CV_16S, dx=1, dy=0 |
Gradiente horizontal (detecta bordes verticales) |
| Sobel Y | Imgproc.Sobel() |
CV_16S, dx=0, dy=1 |
Gradiente vertical (detecta bordes horizontales) |
| Fusión Sobel | Core.addWeighted() |
α=0.5, β=0.5 | Magnitud de gradiente total: G = 0.5·Gx + 0.5·Gy |
Nota técnica: El uso de CvType.CV_16S en Sobel es fundamental — el gradiente puede producir valores negativos que no caben en un uint8. convertScaleAbs() convierte a valor absoluto y normaliza a uint8 para escritura en PNG.
Relación umbral Canny (80:200 = 1:2.5): La proporción recomendada entre umbral bajo y alto está entre 1:2 y 1:3 para equilibrar sensibilidad y precisión en la detección.
Archivo: Rutina3Rostros.java
Implementa detección de rostros humanos en tiempo real usando el clasificador en cascada Viola-Jones (Haar Cascade), uno de los algoritmos más influyentes en visión computacional, propuesto por Viola y Jones en 2001.
foto2.jpg ──► cvtColor(BGR→GRAY) ──► equalizeHist() ──► detectMultiScale() ──► [bounding boxes] ──► rectangle() + putText() ──► foto2_rostros.png
│
haarcascade_frontalface_default.xml
(C:/opencv/build/etc/haarcascades/)
Pipeline de detección:
| Paso | API OpenCV | Propósito |
|---|---|---|
| Conversión a grises | Imgproc.cvtColor() |
Haar funciona sobre intensidad, no color |
| Ecualización de histograma | Imgproc.equalizeHist() |
Normaliza el contraste; mejora detección en condiciones de iluminación variable |
| Detección multi-escala | CascadeClassifier.detectMultiScale() |
Busca rostros en múltiples escalas de la imagen |
| Dibujado de rectángulos | Imgproc.rectangle() |
Marca visualmente cada rostro detectado en verde (0,255,0) |
| Etiquetado | Imgproc.putText() |
Añade la etiqueta "Rostro" sobre cada bounding box |
Parámetros de detectMultiScale:
| Parámetro | Valor | Significado |
|---|---|---|
scaleFactor |
1.05 | Escala de reducción por nivel de la pirámide (1.05 = 5% más pequeño en cada nivel) |
minNeighbors |
2 | Número mínimo de detecciones adyacentes para confirmar un rostro |
minSize |
20×20 px | Tamaño mínimo de rostro a detectar |
maxSize |
sin límite | No se aplica límite superior de tamaño |
El clasificador Haar: Usa haarcascade_frontalface_default.xml, un modelo preentrenado incluido con la instalación de OpenCV que contiene miles de características de Haar organizadas en cascadas de clasificadores débiles (AdaBoost).
Archivo: Rutina4Transformaciones.java
Implementa las cuatro transformaciones geométricas afines más comunes en el preprocesamiento de imágenes para visión artificial.
foto1.png ──┬──► resize(50%) ────────────────────────────────────────────► foto1_redim.png
│
├──► getRotationMatrix2D(centro, 45°, escala=1.0) ──► warpAffine() ──► foto1_rotada.png
│
├──► flip(flipCode=1) [volteo horizontal] ───────────────────► foto1_espejo_h.png
│
└──► flip(flipCode=0) [volteo vertical] ─────────────────────► foto1_espejo_v.png
Transformaciones implementadas:
| Transformación | API OpenCV | Parámetros | Resultado |
|---|---|---|---|
| Redimensionado | Imgproc.resize() |
cols×0.5, rows×0.5 | Imagen al 50% del tamaño original |
| Rotación 45° | Imgproc.getRotationMatrix2D() + warpAffine() |
centro, ángulo=45°, escala=1.0 | Rotación alrededor del centro geométrico |
| Volteo horizontal | Core.flip() |
flipCode=1 |
Espejo sobre eje vertical (izq↔der) |
| Volteo vertical | Core.flip() |
flipCode=0 |
Espejo sobre eje horizontal (arr↕aba) |
Sobre la rotación con warpAffine: Se preservan las dimensiones originales del canvas, lo que implica que las esquinas de la imagen rotada quedan recortadas. Si se deseara que la imagen completa quepa en el canvas, se ajustarían cols y rows de destino con trigonometría.
Convención de flip:
flipCode = 0→ volteo sobre eje X (vertical)flipCode = 1→ volteo sobre eje Y (horizontal)flipCode = -1→ volteo sobre ambos ejes simultáneamente
Las imágenes generadas por cada rutina se almacenan en la carpeta Imagenes/:
| Imagen Original | Escala de Grises | Suavizado Gaussiano | Umbralización Binaria |
|---|---|---|---|
foto1.png |
foto1_gris.png |
foto1_suavizada.png |
foto1_binaria.png |
| Imagen RGB original | Canal de luminancia | Kernel 15×15, ruido eliminado | Umbral global=127 |
| Detector Canny | Gradiente Sobel (X+Y) |
|---|---|
foto1_canny.png |
foto1_sobel.png |
| Bordes finos con histéresis (80-200) | Magnitud del gradiente combinada |
| Imagen de Entrada | Resultado con Detecciones |
|---|---|
foto2.jpg |
foto2_rostros.png |
| Fotografía con personas | Rostros detectados con bounding boxes verdes |
| Redimensionada 50% | Rotada 45° | Espejo Horizontal | Espejo Vertical |
|---|---|---|---|
foto1_redim.png |
foto1_rotada.png |
foto1_espejo_h.png |
foto1_espejo_v.png |
OpenCV usa internamente el orden BGR (Blue-Green-Red) en lugar del convencional RGB. La conversión a escala de grises aplica la fórmula de luminancia ponderada:
Y = 0.114·B + 0.587·G + 0.299·R
Los coeficientes son diferentes porque el ojo humano es más sensible al verde que al rojo y al azul.
El filtro Gaussiano es una convolución con un kernel G(x,y) definido por:
G(x,y) = (1 / 2πσ²) · e^(-(x²+y²) / 2σ²)
Actúa como un filtro pasa-bajos que elimina frecuencias altas (ruido) mientras preserva estructuras de baja frecuencia (gradientes suaves). Es separable, lo que permite implementarlo eficientemente como dos convoluciones 1D.
El algoritmo de Canny (1986) es el detector de bordes óptimo según tres criterios:
- Buena detección: mínima probabilidad de falsos positivos y negativos
- Buena localización: mínima distancia entre borde detectado y borde real
- Respuesta única: un solo punto de respuesta por borde real
Pipeline: suavizado Gaussiano → gradiente Sobel → supresión de no-máximos → umbralización por histéresis.
Aproxima el gradiente de primer orden de la imagen usando kernels 3×3:
Gx = [-1 0 +1] Gy = [-1 -2 -1]
[-2 0 +2] [ 0 0 0]
[-1 0 +1] [+1 +2 +1]
La magnitud total del gradiente es G = √(Gx² + Gy²), aproximada aquí como G ≈ 0.5|Gx| + 0.5|Gy|.
Viola y Jones (2001) propusieron un método de detección de objetos en tiempo real basado en:
- Características rectangulares de Haar: diferencias de sumas de píxeles en regiones rectangulares adyacentes
- Imagen integral: permite calcular cualquier característica rectangular en tiempo O(1)
- AdaBoost: selecciona las características más discriminativas (de 180.000+ posibles, solo unas 6.000 son relevantes)
- Cascada de clasificadores: rechaza rápidamente regiones sin objeto (>99% de ventanas de fondo son eliminadas en los primeros 2-3 estadios)
Las transformaciones afines preservan paralelismo y ratios de distancias. Se representan como matrices 2×3:
[x'] [a b tx] [x]
[y'] = [c d ty] [y]
[1]
Para rotación de ángulo θ con escala s: a=s·cos(θ), b=-s·sin(θ), c=s·sin(θ), d=s·cos(θ). El punto de pivote se controla mediante tx y ty.
| Componente | Versión Requerida | Descripción |
|---|---|---|
| Sistema Operativo | Windows 10/11 x64 | Las DLL nativas de OpenCV son para Windows x64 |
| JDK | Java 8+ (probado en Zulu 17.0.19) | Compatible con javac.source=1.8 |
| OpenCV | 4.10.0 | Instalado en C:\opencv\ |
| NetBeans IDE | 12+ | Para abrir el proyecto directamente |
| Apache Ant | 1.10+ | Incluido en NetBeans; para build desde CLI |
C:\opencv\
├── build\
│ ├── java\
│ │ ├── opencv-4100.jar ← Bindings Java
│ │ └── x64\
│ │ └── opencv_java4100.dll ← Librería nativa (cargada en runtime)
│ └── etc\
│ └── haarcascades\
│ └── haarcascade_frontalface_default.xml ← Requerido por Rutina3
- Descargar el instalador desde opencv.org/releases
- Ejecutar y extraer en
C:\opencv\ - Verificar que existan los archivos:
C:\opencv\build\java\opencv-4100.jarC:\opencv\build\java\x64\opencv_java4100.dll
git clone https://github.com/AlejoTechEngineer/opencv-vision-artificial-java.git
cd opencv-vision-artificial-javaFile→Open Project- Navegar hasta la carpeta
LaboratorioOpenCV/ - NetBeans detectará automáticamente el proyecto Ant
- El classpath ya apunta a
C:\opencv\build\java\opencv-4100.jar(verproject.properties)
En nbproject/project.properties la línea:
run.jvmargs=-Djava.library.path=C:\\opencv\\build\\java\\x64
apunta al directorio que contiene opencv_java4100.dll. Si OpenCV está en otra ruta, actualizar este valor.
Colocar en Imagenes/:
foto1.png— cualquier imagen PNG para las rutinas 1, 2 y 4foto2.jpg— fotografía con uno o más rostros frontales para la rutina 3
Ejecutar LaboratorioOpenCV.java (clase principal del proyecto):
OpenCV version: 4.10.0-dev
Instalacion correcta.
Cada clase tiene su propio main. En NetBeans, click derecho sobre el archivo → Run File.
Rutina 1:
Ruta: C:/Users/.../Imagenes/
Rutina 1 completada.
Dimensiones: 1080 x 1920
Genera: foto1_gris.png, foto1_suavizada.png, foto1_binaria.png
Rutina 2:
Rutina 2 completada.
Bordes detectados con Canny y Sobel.
Genera: foto1_canny.png, foto1_sobel.png
Rutina 3:
Rostros detectados: N
Rutina 3 completada.
Genera: foto2_rostros.png con bounding boxes verdes sobre cada rostro
Rutina 4:
Rutina 4 completada.
Tam. original: 1920 x 1080
Tam. redimensionado: 960 x 540
Genera: foto1_redim.png, foto1_rotada.png, foto1_espejo_h.png, foto1_espejo_v.png
cd LaboratorioOpenCV
ant clean
ant compile
ant runopencv-vision-artificial-java/
│
├── README.md
│
├── LaboratorioOpenCV/ ← Proyecto NetBeans/Ant
│ ├── build.xml ← Script de build Ant
│ ├── manifest.mf ← Manifest del JAR
│ │
│ ├── src/
│ │ └── laboratorioopencv/
│ │ ├── LaboratorioOpenCV.java ← Main: verificación de OpenCV
│ │ ├── Rutina1Basico.java ← Grises, Gaussiano, umbral
│ │ ├── Rutina2Bordes.java ← Canny, Sobel X+Y
│ │ ├── Rutina3Rostros.java ← Haar Cascade face detection
│ │ └── Rutina4Transformaciones.java ← Resize, rotate, flip
│ │
│ ├── nbproject/
│ │ ├── project.xml ← Metadata del proyecto
│ │ ├── project.properties ← Configuración de build/run
│ │ ├── build-impl.xml ← Implementación Ant generada
│ │ └── private/
│ │ └── private.properties ← Rutas locales de la máquina
│ │
│ └── build/ ← Directorio generado (compilación)
│ └── classes/
│ └── laboratorioopencv/
│ ├── LaboratorioOpenCV.class
│ ├── Rutina1Basico.class
│ ├── Rutina2Bordes.class
│ ├── Rutina3Rostros.class
│ └── Rutina4Transformaciones.class
│
├── Imagenes/ ← Imágenes de entrada y resultados
│ ├── foto1.png ← Imagen base (entrada)
│ ├── foto2.jpg ← Fotografía con rostros (entrada)
│ ├── foto1_gris.png ← Salida: escala de grises
│ ├── foto1_suavizada.png ← Salida: Gaussian blur
│ ├── foto1_binaria.png ← Salida: umbralización binaria
│ ├── foto1_canny.png ← Salida: detector Canny
│ ├── foto1_sobel.png ← Salida: gradiente Sobel
│ ├── foto2_rostros.png ← Salida: rostros detectados
│ ├── foto1_redim.png ← Salida: redimensionada 50%
│ ├── foto1_rotada.png ← Salida: rotación 45°
│ ├── foto1_espejo_h.png ← Salida: volteo horizontal
│ └── foto1_espejo_v.png ← Salida: volteo vertical
│
└── Desarrollo Proyecto Alejandro De Mendoza.pdf ← Informe académico del laboratorio
| Tecnología | Versión | Rol en el proyecto |
|---|---|---|
| Java SE | 8/17 (Zulu 17.0.19) | Lenguaje de programación principal |
| OpenCV | 4.10.0 | Librería de visión computacional (core, imgproc, imgcodecs, objdetect) |
| NetBeans IDE | 12+ | Entorno de desarrollo; gestión del proyecto |
| Apache Ant | 1.10+ | Sistema de automatización de build |
| Haar Cascade XML | OpenCV built-in | Modelo preentrenado para detección de rostros frontales |
| Módulo | Clases importadas | Propósito |
|---|---|---|
core |
Core, Mat, MatOfRect, Point, Rect, Scalar, Size, CvType |
Tipos de datos fundamentales y operaciones matriciales |
imgproc |
Imgproc |
Procesamiento de imágenes (filtros, detección, transformaciones) |
imgcodecs |
Imgcodecs |
Lectura y escritura de imágenes en disco |
objdetect |
CascadeClassifier |
Detección de objetos con clasificadores en cascada |
Alejandro De Mendoza
Ingeniería Informática
Sistemas Multiagente y Percepción Computacional