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
JavaScript
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