openenv-image-optimizer / environment.py
Tanishq71's picture
Upload 2 files
5ea4932 verified
Raw
History Blame Contribute Delete
3.91 kB
import math
from typing import Optional
from pydantic import BaseModel
from models import ImageAction, ImageObservation
class ActionResult(BaseModel):
observation: ImageObservation
reward: float
done: bool
error: Optional[str] = None
class ImageOptimizerEnv:
def __init__(self, task_id: str):
self.task_id = task_id
self.max_steps = 8
self.reset_state()
def reset_state(self):
self.step_count = 0
self.done = False
# Initialize tasks with distinct mathematical corruption profiles
if self.task_id == "task_1_easy_brightness":
self.brightness = 0.2
self.noise = 0.05
self.contrast = 0.8
elif self.task_id == "task_2_medium_noise":
self.brightness = 0.6
self.noise = 0.85
self.contrast = 0.4
elif self.task_id == "task_3_hard_pipeline":
self.brightness = 0.1
self.noise = 0.9
self.contrast = 0.2
else:
self.brightness = 0.5
self.noise = 0.5
self.contrast = 0.5
self.accuracy = self._calculate_accuracy()
return self._get_obs()
async def reset(self) -> ActionResult:
obs = self.reset_state()
return ActionResult(observation=obs, reward=0.0, done=False)
def _calculate_accuracy(self) -> float:
# Ideal states: Brightness ~0.6, Noise ~0.0, Contrast ~0.9
b_penalty = abs(0.6 - self.brightness) * 1.5
n_penalty = self.noise * 2.0
c_penalty = abs(0.9 - self.contrast) * 1.2
base = 1.0 - (b_penalty + n_penalty + c_penalty)
# Strict OpenEnv Clamping: Must be between 0 and 1 (exclusive)
return max(0.01, min(0.99, base))
def _get_obs(self) -> ImageObservation:
return ImageObservation(
task_id=self.task_id,
avg_brightness=round(self.brightness, 2),
noise_variance=round(self.noise, 2),
contrast_ratio=round(self.contrast, 2),
current_accuracy=round(self.accuracy, 3),
step_count=self.step_count
)
async def step(self, action: ImageAction) -> ActionResult:
if self.done:
return ActionResult(observation=self._get_obs(), reward=0.0, done=True, error="Episode already finished.")
self.step_count += 1
prev_acc = self.accuracy
op = action.operation
i = action.intensity
# Mathematical simulation of cv2 operations
if op == "increase_brightness":
self.brightness = min(1.0, self.brightness + (0.4 * i))
elif op == "decrease_brightness":
self.brightness = max(0.0, self.brightness - (0.4 * i))
elif op == "apply_denoise":
self.noise = max(0.0, self.noise - (0.5 * i))
self.contrast = max(0.0, self.contrast - (0.1 * i)) # Denoising inherently blurs
elif op == "increase_contrast":
self.contrast = min(1.0, self.contrast + (0.4 * i))
self.noise = min(1.0, self.noise + (0.1 * i)) # Boosting contrast highlights noise
self.accuracy = self._calculate_accuracy()
if op == "submit_pipeline" or self.step_count >= self.max_steps:
self.done = True
# Final grading reward
final_reward = self.accuracy * 10.0
return ActionResult(observation=self._get_obs(), reward=final_reward, done=True)
# Dense partial reward: positive for acc gain, negative for acc loss
delta = self.accuracy - prev_acc
reward = delta * 5.0
return ActionResult(observation=self._get_obs(), reward=reward, done=False)
async def close(self):
pass