Loading s5obj_lang_labo_5...
static void TestFilter( Image image, IImageFilter filter, string suffix) { Image result = filter.Apply(image); string path = "results/" + image.Name + "_" + suffix + ".ppm"; result.Save(path); }
TestFilter(image, new GrayFilter(), "gray"); TestFilter(image, new InvertFilter(),"invert");
private float ApplyContrast(float v) { float res = (v - 0.5f) * factor + 0.5f; return Math.Clamp(res, 0f, 1f); }
public Image Apply(Image input) { int width = input.GetWidth(); int height = input.GetHeight(); string name = input.GetName();
Image result = new Image(width, height, name);
for (int y = 0; y < input.height; y++) { for (int x = 0; x < input.width; x++) { float sumR = 0, sumG = 0, sumB = 0; int count = 0;
for (int dy = -radius; dy <= radius; dy++) { for (int dx = -radius; dx <= radius; dx++) { int nx = x + dx; int ny = y + dy;
if (nx >= 0 && nx < width && ny >= 0 && ny < height) { Color c = input.GetPixel(nx, ny);
sumR += c.R; sumG += c.G; sumB += c.B;
count++; } } }
var blurred = new Color( sumR / count, sumG / count, sumB / count );
result.SetPixel(x, y, blurred); } }
return result; }
private float Gaussian() { double u1 = 1.0 - rand.NextDouble(); double u2 = 1.0 - rand.NextDouble();
double val = Math.Sqrt(-2.0 * Math.Log(u1)) * Math.Cos(2.0 * Math.PI * u2);
return (float)val; }
static void PipeLineOld(Image image) { }
Processor: Old Image: Lena Blur(radius=1) Contrast(factor=0.7) Sepia GaussianNoise(sigma=0.03) Contrast(factor=0.9) ############################
use crate::filtres::IImageFilter; use crate::image::Image; use crate::logger::Logger;
use std::cell::RefCell; use std::rc::Rc;
pub struct ImageProcessor { name: String, filters: Vec<Box<dyn IImageFilter>>, logger: Rc<RefCell<Logger>>, }
impl ImageProcessor { pub fn new( name: String, logger: Rc<RefCell<Logger>>, ) -> Self { Self { name, filters: Vec::new(), logger, } }
pub fn name(&self) -> &str { &self.name }
pub fn add_filter( &mut self, filter: Box<dyn IImageFilter>, ) { self.filters.push(filter); }
pub fn process( &mut self, input: &Image, ) -> Image { let mut current = input.clone();
self.logger .borrow_mut() .log(&format!("Processor: {}", self.name)); self.logger .borrow_mut() .log(&format!("Image: {}", current.name()));
for filter in &self.filters { current = filter.apply(¤t); self.logger.borrow_mut().log(filter.description()); }
self.logger.borrow_mut().log("######################");
current } }
use std::fs::File; use std::io::{BufWriter, Write};
pub struct Logger { writer: BufWriter<File>, }
impl Logger { pub fn new(path: &str) -> Self { let file = File::create(path).unwrap();
Self { writer: BufWriter::new(file), } }
pub fn log( &mut self, message: &str, ) { writeln!(self.writer, "{message}").unwrap(); self.writer.flush().unwrap(); }
// Unlike C#, no close() method is needed. // In Rust, resources are released automatically when an object goes out of scope. // The file is then flushed and closed automatically. }
fn main() { let logger = Rc::new(RefCell::new(Logger::new("results/processing.log"))); logger.borrow_mut().log("Logger initialized.");
// Two ImageProcessors (p1 and p2) are created to demonstrate that they share the same logger.
let img1 = Image::from_file("data/Lena.ppm");
let mut p1 = ImageProcessor::new("Basic pipeline".to_string(), Rc::clone(&logger)); p1.add_filter(Box::new(GrayFilter)); p1.add_filter(Box::new(InvertFilter)); let result = p1.process(&img1); let path = format!("results/{}_{}.ppm", img1.name(), p1.name()); result.save(&path);
let img2 = Image::from_file("data/Boat.ppm");
let mut p2 = ImageProcessor::new("Basic pipeline".to_string(), Rc::clone(&logger)); p2.add_filter(Box::new(InvertFilter)); let result = p2.process(&img2); let path = format!("results/{}_{}.ppm", img2.name(), p2.name()); result.save(&path); }
pub struct ImageProcessor { name: String, filters: Vec<Box<dyn IImageFilter>>, logger: &'a mut Logger, <------------ }
impl<'a> ImageProcessor<'a> { pub fn new(name: &str, logger: &'a mut Logger) -> Self { Self { name: name.to_string(), filters: Vec::new(), logger, } } ... }
fn main() { let mut logger = Logger::new("processing.log");
let mut processor = ImageProcessor::new("Basic pipeline", &mut logger);
// ... }
pub struct ImageProcessor { name: String, filters: Vec<Box<dyn ImageFilter>>, logger: Rc<RefCell<Logger>>, }
let logger = Rc::new( RefCell::new(Logger::new("processing.log")) );
let mut p1 = ImageProcessor::new("Pipeline 1", Rc::clone(&logger)); let mut p2 = ImageProcessor::new("Pipeline 2", Rc::clone(&logger));
// Borrow the shared Logger mutably before writing to it. logger.borrow_mut().log("Logger initialized.");
// static methods in Program class
static void TestFilter( Image image, IImageFilter filter, string suffix) { Image result = filter.Apply(image); string path = "results/" + image.GetName() + "_" + suffix + ".ppm"; result.Save(path); }
static void PipeLineOld(Image image, Logger logger) { ImageProcessor processor = new ImageProcessor("Old", logger); processor.AddFilter(new BlurFilter(1)); processor.AddFilter(new ContrastFilter(0.7f)); processor.AddFilter(new SepiaFilter()); processor.AddFilter(new GaussianNoiseFilter(0.03f)); processor.AddFilter(new ContrastFilter(0.9f)); Image result = processor.Process(image); string path = "results/" + image.GetName() + "_" + processor.GetName() + ".ppm"; result.Save(path); }
static void PipeLineVintage(Image image, Logger logger) { ImageProcessor processor = new ImageProcessor("Vintage", logger); processor.AddFilter(new ContrastFilter(0.8f)); processor.AddFilter(new SepiaFilter()); processor.AddFilter(new GaussianNoiseFilter(0.04f)); processor.AddFilter(new BlurFilter(1)); Image result = processor.Process(image); string path = "results/" + image.GetName() + "_" + processor.GetName() + ".ppm"; result.Save(path); }
static void Main() { Logger logger = new Logger("results/log.txt"); logger.Log("~~~~~~~~~~ Image Processing ~~~~~~~~~~");
Image image = new Image("data/Lena.ppm");
TestFilter(image, new GaussianNoiseFilter(0.5f),"gaussian");
PipeLineOld(image, logger); PipeLineVintage(image, logger);
logger.Close(); }
namespace ImageProcessing;
public class ImageProcessor { private string name; private List<IImageFilter> filters; private Logger logger;
public ImageProcessor(string name, Logger logger) { this.name = name; this.filters = new List<IImageFilter>(); this.logger = logger; }
public string GetName() { return name; }
public void AddFilter(IImageFilter filter) { filters.Add(filter); }
public Image Process(Image input) { Image current = input; logger.Log($"Processor: {name}"); logger.Log($"Image: {input.GetName()}");
foreach (var f in filters) { current = f.Apply(current); logger.Log(f.Description()); }
logger.Log("######################"); return current; } }
using System.IO;
namespace ImageProcessing;
public class Logger { private StreamWriter writer;
public Logger(string path) { writer = new StreamWriter(path); }
public void Log(string message) { writer.WriteLine(message); }
public void Close() { writer.Close(); } }
namespace ImageProcessing;
public interface IImageFilter { Image Apply(Image input); string Description(); }
// Gray and Invert filters
public class ContrastFilter : IImageFilter { private float factor;
public ContrastFilter(float factor) { if (factor < 0) throw new ArgumentException("Factor must be >= 0");
this.factor = factor; }
public Image Apply(Image input) { int width = input.GetWidth(); int height = input.GetHeight(); string name = input.GetName();
Image result = new Image(width, height, name);
for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { var c = input.GetPixel(x, y);
float r = ApplyContrast(c.GetR()); float g = ApplyContrast(c.GetG()); float b = ApplyContrast(c.GetB());
result.SetPixel(x, y, new Color(r, g, b)); } }
return result; }
private float ApplyContrast(float v) { float res = (v - 0.5f) * factor + 0.5f; return Math.Clamp(res, 0f, 1f); }
public string Description() { return $"Contrast(factor={factor})"; } }
public class SepiaFilter : IImageFilter { public Image Apply(Image input) { int width = input.GetWidth(); int height = input.GetHeight(); string name = input.GetName();
Image result = new Image(width, height, name);
for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { var c = input.GetPixel(x, y);
float r = 0.393f * c.GetR() + 0.769f * c.GetG() + 0.189f * c.GetB(); float g = 0.349f * c.GetR() + 0.686f * c.GetG() + 0.168f * c.GetB(); float b = 0.272f * c.GetR() + 0.534f * c.GetG() + 0.131f * c.GetB();
result.SetPixel(x, y, new Color( Math.Clamp(r, 0f, 1f), Math.Clamp(g, 0f, 1f), Math.Clamp(b, 0f, 1f) )); } }
return result; }
public string Description() { return "Sepia"; } }
public class BlurFilter : IImageFilter { private int radius;
public BlurFilter(int radius) { if (radius < 1) throw new ArgumentException("Radius must be >= 1");
this.radius = radius; }
public Image Apply(Image input) { int width = input.GetWidth(); int height = input.GetHeight(); string name = input.GetName();
Image result = new Image(width, height, name);
for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { float sumR = 0, sumG = 0, sumB = 0; int count = 0;
for (int dy = -radius; dy <= radius; dy++) { for (int dx = -radius; dx <= radius; dx++) { int nx = x + dx; int ny = y + dy;
if (nx >= 0 && nx < width && ny >= 0 && ny < height) { var c = input.GetPixel(nx, ny);
sumR += c.GetR(); sumG += c.GetG(); sumB += c.GetB();
count++; } } }
var blurred = new Color( sumR / count, sumG / count, sumB / count );
result.SetPixel(x, y, blurred); } }
return result; }
public string Description() { return $"Blur(radius={radius})"; } }
public class GaussianNoiseFilter : IImageFilter { /*sigma = 0.03 → light sigma = 0.05 → perfect sigma = 0.1 → strong */ private float sigma; private Random rand = new Random();
public GaussianNoiseFilter(float sigma) { this.sigma = sigma; }
public Image Apply(Image input) { int width = input.GetWidth(); int height = input.GetHeight(); string name = input.GetName();
Image result = new Image(width, height, name);
for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { var c = input.GetPixel(x, y);
float r = Math.Clamp(c.GetR() + Gaussian() * sigma, 0f, 1f); float g = Math.Clamp(c.GetG() + Gaussian() * sigma, 0f, 1f); float b = Math.Clamp(c.GetB() + Gaussian() * sigma, 0f, 1f);
result.SetPixel(x, y, new Color(r, g, b)); } }
return result; }
private float Gaussian() { double u1 = 1.0 - rand.NextDouble(); double u2 = 1.0 - rand.NextDouble();
double val = Math.Sqrt(-2.0 * Math.Log(u1)) * Math.Cos(2.0 * Math.PI * u2);
return (float)val; }
public string Description() { return $"GaussianNoise(sigma={sigma})"; } }