UNPKG

react-native-guided-camera

Version:

A React Native component for agricultural camera guidance with sensor-based motion detection, orientation tracking, and real-time feedback.

303 lines 11.5 kB
export class RealtimeBrightnessDetector { constructor(onLightingChange, config = {}) { var _a; this.analysisInterval = null; this.isActive = false; this.cameraRef = null; // Data history for smoothing this.brightnessHistory = []; this.onLightingChange = onLightingChange; this.config = { updateInterval: config.updateInterval || 2000, // 2 second updates historySize: config.historySize || 5, smoothingFactor: config.smoothingFactor || 0.8, enableTimeBasedEstimation: (_a = config.enableTimeBasedEstimation) !== null && _a !== void 0 ? _a : true, }; this.lastMetrics = { meanLuminance: 128, contrastRatio: 3.0, shadowDetail: 20, highlightClipping: 0, colorTemperature: 5500, quality: "fair", isOptimal: false, recommendation: "Analyzing lighting conditions...", score: 50, source: "estimated", }; } async start(cameraRef) { if (this.isActive) return; this.cameraRef = cameraRef; try { console.log("Real-time brightness detector starting..."); this.startRealtimeAnalysis(); this.isActive = true; console.log("Real-time brightness detector started successfully"); } catch (error) { console.error("Failed to start brightness detector:", error); this.isActive = true; } } startRealtimeAnalysis() { this.analysisInterval = setInterval(async () => { try { const brightnessData = await this.analyzeCurrentLighting(); this.handleBrightnessUpdate(brightnessData); } catch (error) { console.error("Error analyzing brightness:", error); // Continue with time-based estimation const fallbackData = this.getTimeBasedEstimation(); this.handleBrightnessUpdate(fallbackData); } }, this.config.updateInterval); } async analyzeCurrentLighting() { var _a; // If camera reference is available, try to analyze the preview if ((_a = this.cameraRef) === null || _a === void 0 ? void 0 : _a.current) { try { // Try to get a quick preview analysis without taking a full picture const previewData = await this.getPreviewBrightness(); if (previewData) { return previewData; } } catch (error) { console.log("Preview analysis failed, using estimation"); } } // Fallback to intelligent estimation return this.getTimeBasedEstimation(); } async getPreviewBrightness() { try { // Take a very small, low quality image for analysis only const image = await this.cameraRef.current.takePictureAsync({ quality: 0.1, // Very low quality for speed base64: true, skipProcessing: true, }); if (image === null || image === void 0 ? void 0 : image.base64) { const brightness = await this.analyzeImageBrightness(image.base64); return brightness; } } catch (error) { console.log("Quick image analysis failed:", error); } return null; } async analyzeImageBrightness(base64Image) { // Convert base64 to analyze brightness // This is a simplified analysis - in production you'd use more sophisticated methods // Estimate brightness from base64 length and characteristics const imageSize = base64Image.length; const compressionRatio = imageSize / 1000; // Rough estimate // Dark images compress better (smaller size), bright images are larger let estimatedLuminance = Math.min(255, Math.max(30, compressionRatio * 15)); // Analyze base64 content for more clues const brightChars = (base64Image.match(/[M-Z]/g) || []).length; const darkChars = (base64Image.match(/[A-L]/g) || []).length; const brightRatio = brightChars / (brightChars + darkChars); // Adjust luminance based on character analysis estimatedLuminance = estimatedLuminance * 0.7 + brightRatio * 200 * 0.3; // Estimate contrast from luminance variation const contrast = this.estimateContrastFromLuminance(estimatedLuminance); return { luminance: estimatedLuminance, contrast: contrast, timestamp: Date.now(), }; } getTimeBasedEstimation() { const hour = new Date().getHours(); const minute = new Date().getMinutes(); let baseLuminance; // More realistic lighting estimation based on time if (hour >= 6 && hour < 9) { // Early morning - gradually increasing baseLuminance = 60 + (hour - 6) * 25 + (minute / 60) * 15; } else if (hour >= 9 && hour < 17) { // Daytime - bright but with some variation baseLuminance = 140 + Math.sin(((hour - 9) * Math.PI) / 8) * 40; } else if (hour >= 17 && hour < 20) { // Evening - gradually decreasing baseLuminance = 120 - (hour - 17) * 20 - (minute / 60) * 15; } else if (hour >= 20 && hour < 22) { // Twilight baseLuminance = 70 - (hour - 20) * 15; } else { // Night - very low baseLuminance = 40 + Math.random() * 20; } // Add some realistic variation const variation = (Math.random() - 0.5) * 30; const finalLuminance = Math.max(25, Math.min(255, baseLuminance + variation)); const contrast = this.estimateContrastFromLuminance(finalLuminance); return { luminance: finalLuminance, contrast: contrast, timestamp: Date.now(), }; } estimateContrastFromLuminance(luminance) { if (luminance > 180) { return 1.8 + Math.random() * 0.8; // Bright = often low contrast } else if (luminance > 120) { return 2.5 + Math.random() * 1.0; // Good lighting = good contrast } else if (luminance > 80) { return 2.0 + Math.random() * 1.2; // Dim = variable contrast } else { return 1.2 + Math.random() * 0.6; // Dark = poor contrast } } handleBrightnessUpdate(brightnessData) { // Add to history this.brightnessHistory.push(brightnessData); if (this.brightnessHistory.length > this.config.historySize) { this.brightnessHistory.shift(); } // Apply smoothing const smoothedLuminance = this.applySmoothing(brightnessData.luminance); const smoothedContrast = this.applySmoothing(brightnessData.contrast); // Calculate comprehensive metrics const metrics = this.calculateLightingMetrics(smoothedLuminance, smoothedContrast); this.lastMetrics = metrics; this.onLightingChange(metrics); } applySmoothing(currentValue) { if (this.brightnessHistory.length <= 1) return currentValue; const previousValue = this.lastMetrics.meanLuminance; return (this.config.smoothingFactor * previousValue + (1 - this.config.smoothingFactor) * currentValue); } calculateLightingMetrics(luminance, contrast) { // Calculate individual quality scores const luminanceScore = this.scoreLuminance(luminance); const contrastScore = this.scoreContrast(contrast); // Estimate other metrics const shadowDetail = Math.max(0, Math.min(50, (luminance - 50) * 0.4)); const highlightClipping = luminance > 220 ? (luminance - 220) * 0.5 : 0; const colorTemperature = this.estimateColorTemperature(luminance); // Overall score const overallScore = (luminanceScore + contrastScore) / 2; // Determine quality level and recommendations let quality; let isOptimal; let recommendation; if (overallScore >= 85) { quality = "excellent"; isOptimal = true; recommendation = "🌟 Excellent lighting conditions!"; } else if (overallScore >= 70) { quality = "good"; isOptimal = true; recommendation = "✅ Good lighting for recording"; } else if (overallScore >= 55) { quality = "fair"; isOptimal = false; recommendation = "⚠️ Adequate lighting - could be improved"; } else if (overallScore >= 35) { quality = "poor"; isOptimal = false; recommendation = "💡 Poor lighting - add more light"; } else { quality = "very_poor"; isOptimal = false; recommendation = "🔦 Very poor lighting - insufficient for recording"; } return { meanLuminance: Math.round(luminance), contrastRatio: Math.round(contrast * 10) / 10, shadowDetail: Math.round(shadowDetail), highlightClipping: Math.round(highlightClipping), colorTemperature: Math.round(colorTemperature), quality, isOptimal, recommendation, score: Math.round(overallScore), source: this.cameraRef ? "realtime" : "estimated", }; } scoreLuminance(luminance) { // Optimal range: 120-180 if (luminance >= 120 && luminance <= 180) { return 100; } else if (luminance >= 100 && luminance <= 200) { return 80; } else if (luminance >= 80 && luminance <= 220) { return 60; } else if (luminance >= 60 && luminance <= 240) { return 40; } else { return 20; } } scoreContrast(contrast) { // Optimal range: 2.0-4.0 if (contrast >= 2.0 && contrast <= 4.0) { return 100; } else if (contrast >= 1.5 && contrast <= 5.0) { return 80; } else if (contrast >= 1.2 && contrast <= 6.0) { return 60; } else { return 40; } } estimateColorTemperature(luminance) { // Estimate color temperature based on brightness // This is a very rough estimation if (luminance > 180) { return 6500; // Bright daylight } else if (luminance > 120) { return 5500; // Good daylight } else if (luminance > 80) { return 4500; // Indoor/cloudy } else { return 3500; // Warm indoor lighting } } stop() { if (this.analysisInterval) { clearInterval(this.analysisInterval); this.analysisInterval = null; } this.brightnessHistory = []; this.isActive = false; console.log("Real-time brightness detector stopped"); } getLastMetrics() { return this.lastMetrics; } isRunning() { return this.isActive; } } //# sourceMappingURL=realtimeBrightnessDetectorV2.js.map