The Angular PWA Demo includes computer vision capabilities powered by OpenCV (C++ backend and OpenCV.js) and OCR functionality using Tesseract.
Overview
OpenCV Image processing and shape detection
OCR Text extraction from images
Fractals Julia set fractal generation
Shape detection Detect circles, rectangles, and triangles
OpenCV features
The application uses OpenCV for image processing through both a C++ backend and client-side OpenCV.js.
Backend configuration
The Computer Vision service connects to a C++ backend for processing:
// src/app/_services/__AI/ComputerVisionService/Computer-Vision.service.ts
@ Injectable ({ providedIn: 'root' })
export class ComputerVisionService extends BaseService {
private readonly http = inject ( HttpClient );
private readonly _configService = inject ( ConfigService );
private readonly __baseUrl = ` ${ this . _configService . getConfigValue ( 'baseUrlNetCoreCPPEntry' ) } api/computervision/` ;
_OpenCv_GetAppVersion () : Observable < string > {
return this . http . get < string >( ` ${ this . __baseUrl } GetAppVersion` , this . HTTPOptions_Text );
}
_OpenCv_GetAPIVersion () : Observable < string > {
return this . http . get < string >( ` ${ this . __baseUrl } GetAPIVersion` , this . HTTPOptions_Text );
}
_OpenCv_GetCPPSTDVersion () : Observable < string > {
return this . http . get < string >( ` ${ this . __baseUrl } GetCPPSTDVersion` , this . HTTPOptions_Text );
}
}
Image upload and processing
_OpenCv_CPP_uploadBase64Image ( base64Image : string ): Observable < OCRResponse > {
return this.http.post<OCRResponse>( ` ${ this . __baseUrl } uploadOpenCv` , { base64Image });
}
The service accepts base64-encoded images for processing. Convert your images to base64 before uploading.
Shape detection
Client-side shape detection using OpenCV.js with contour analysis:
Implementation
_OpenCv_js_detectShapes ( imageElement : HTMLImageElement ): string [] {
const shapes : string [] = [];
const cv = ( window as any ). cv ;
if ( ! cv ) return [ 'OpenCV not loaded' ];
// Read image
const src = cv . imread ( imageElement );
const gray = new cv . Mat ();
const edges = new cv . Mat ();
// Convert to grayscale
cv . cvtColor ( src , gray , cv . COLOR_RGBA2GRAY , 0 );
// Edge detection
cv . Canny ( gray , edges , 50 , 150 , 3 , false );
// Find contours
const contours = new cv . MatVector ();
const hierarchy = new cv . Mat ();
cv . findContours ( edges , contours , hierarchy , cv . RETR_EXTERNAL , cv . CHAIN_APPROX_SIMPLE );
// Classify shapes
for ( let i = 0 ; i < contours . size (); i ++ ) {
const approx = new cv . Mat ();
cv . approxPolyDP ( contours . get ( i ), approx , 0.04 * cv . arcLength ( contours . get ( i ), true ), true );
if ( approx . rows === 3 ) shapes . push ( '[Triangle]' );
else if ( approx . rows === 4 ) shapes . push ( '[Rectangle/Square]' );
else if ( approx . rows > 4 ) shapes . push ( '[Circle]' );
approx . delete ();
}
// Cleanup
src . delete ();
gray . delete ();
edges . delete ();
contours . delete ();
hierarchy . delete ();
return shapes ;
}
Shape classification logic
Triangle detection
Rectangle detection
Circle detection
// Triangles have 3 vertices after polygon approximation
if ( approx . rows === 3 ) {
shapes . push ( '[Triangle]' );
}
// Rectangles and squares have 4 vertices
if ( approx . rows === 4 ) {
shapes . push ( '[Rectangle/Square]' );
}
// Circles have many vertices after approximation
if ( approx . rows > 4 ) {
shapes . push ( '[Circle]' );
}
OCR (Optical Character Recognition)
Extract text from images using Tesseract OCR with support for both C++ and Node.js backends.
Service implementation
Service
C++ Backend
Node.js Backend
// src/app/_services/__AI/OCRService/ocr.service.ts
export interface OCRResponse {
message : string ;
status ?: string ;
data ?: any ;
}
@ Injectable ({
providedIn: 'root'
})
export class OCRService extends BaseService {
private readonly http = inject ( HttpClient );
private readonly _configService = inject ( ConfigService );
private readonly __baseUrl = ` ${ this . _configService . getConfigValue ( 'baseUrlNetCoreCPPEntry' ) } api/ocr/` ;
// Version information
_GetTesseract_CPPSTDVersion () : Observable < string > {
return this . http . get < string >( ` ${ this . __baseUrl } GetCPPSTDVersion` , this . HTTPOptions_Text );
}
_GetTesseract_AppVersion () : Observable < string > {
return this . http . get < string >( ` ${ this . __baseUrl } GetAppVersion` , this . HTTPOptions_Text );
}
_GetTesseract_APIVersion () : Observable < string > {
return this . http . get < string >( ` ${ this . __baseUrl } GetAPIVersion` , this . HTTPOptions_Text );
}
}
Usage example
export class VisionComponent {
constructor ( private ocrService : OCRService ) {}
processImage ( imageFile : File ) {
// Convert image to base64
const reader = new FileReader ();
reader . onload = ( e : any ) => {
const base64Image = e . target . result . split ( ',' )[ 1 ];
// Send to OCR service
this . ocrService . uploadBase64ImageCPP ( base64Image ). subscribe ({
next : ( response : OCRResponse ) => {
console . log ( 'OCR Result:' , response . message );
console . log ( 'Extracted text:' , response . data );
},
error : ( error ) => {
console . error ( 'OCR Error:' , error );
}
});
};
reader . readAsDataURL ( imageFile );
}
}
OCR accuracy depends on image quality. Use high-resolution, well-lit images with clear text for best results.
Fractal generation
Generate Julia set fractals with configurable parameters.
API
_OpenCv_GetFractal (
p_maxIterations : number ,
p_realPart : number ,
p_imagPart : number
): Observable < Blob > {
const url = ` ${ this . __baseUrl } generatejuliaparams/?maxIterations= ${ p_maxIterations } &realPart= ${ p_realPart } &imagPart= ${ p_imagPart } ` ;
return this.http.get( url , { responseType : 'blob' });
}
Parameters
Maximum number of iterations for fractal calculation. Higher values produce more detail but take longer to compute.
Real part of the complex constant c in the Julia set equation z = z² + c.
Imaginary part of the complex constant c in the Julia set equation z = z² + c.
Example usage
export class FractalComponent {
constructor ( private cvService : ComputerVisionService ) {}
generateFractal () {
const maxIterations = 256 ;
const realPart = - 0.7 ;
const imagPart = 0.27015 ;
this . cvService . _OpenCv_GetFractal ( maxIterations , realPart , imagPart )
. subscribe ({
next : ( blob : Blob ) => {
// Create image URL from blob
const imageUrl = URL . createObjectURL ( blob );
// Display in img element
const imgElement = document . getElementById ( 'fractal' ) as HTMLImageElement ;
imgElement . src = imageUrl ;
},
error : ( error ) => {
console . error ( 'Fractal generation error:' , error );
}
});
}
}
Image processing pipeline
Type definitions
// OCR Response interface
export interface OCRResponse {
message : string ; // Extracted text or status message
status ?: string ; // Success/error status
data ?: any ; // Additional processing data
}
// Base service with HTTP options
export class BaseService {
protected HTTPOptions_Text = {
headers: new HttpHeaders ({
'Content-Type' : 'text/plain'
}),
responseType: 'text' as 'json'
};
}
Best practices
Resize large images before processing to reduce bandwidth
Use JPEG compression for photographs, PNG for screenshots
Validate image format before base64 conversion
Handle CORS issues when loading external images
Use high-contrast images for better accuracy
Apply image preprocessing (grayscale, threshold) before OCR
Consider image orientation and rotation
Test with different backends (C++, Node.js) for best results
Load OpenCV.js asynchronously to avoid blocking
Clean up Mat objects to prevent memory leaks
Use Web Workers for intensive processing
Fallback to backend processing if client is slow
Validate backend availability before processing
Provide user feedback during long operations
Handle network errors gracefully
Implement retry logic for failed requests
Client-side vs Server-side processing:
OpenCV.js (client-side): Fast for simple operations, no server load, works offline
C++ backend: Better for complex operations, consistent performance, reduced client memory usage
Node.js backend: Good balance, easier deployment, TypeScript integration
Choose based on your use case and infrastructure.
VisionHUB component
The VisionHUBComponent provides a unified interface for all computer vision and OCR features. It combines camera capture, signature pad, file upload, and processing into a single interactive component.
Key features
Multi-source input:
Camera capture (front/back camera switching)
Signature pad with drawing capabilities
File upload from device
Image URL input
Dual feature modes:
OCR mode : Text extraction with Tesseract (Node.js or C++ backend)
Computer Vision mode : Shape detection with OpenCV (Node.js or C++ backend)
Component structure:
// src/app/_modules/_Demos/_DemosFeatures/miscelaneous/VisionHUB/vision-HUB.component.ts
export class VisionHUBComponent extends BaseReferenceComponent {
readonly selectedFeature = signal < number >( 1 ); // 1=OCR, 2=CV
readonly selectedSource = signal < number >( 0 ); // Input source
readonly selectedEngine = signal < number >( 1 ); // Backend engine
readonly capturedImage = signal < string | null >( null );
// Computed engine options based on feature
readonly engineList = computed (() => {
return this . selectedFeature () === 1
? [{ id: 1 , label: 'Tesseract -> Node.js' },
{ id: 2 , label: 'Tesseract -> C++' }]
: [{ id: 3 , label: 'OpenCV -> Node.js' },
{ id: 4 , label: 'OpenCV -> C++' }];
});
}
VisionHUB uses Angular 21 signals and computed values for reactive UI updates. The engine list automatically adapts when switching between OCR and Computer Vision modes.
Machine learning TensorFlow and AI features
File generation Export processed images to PDF