"""Run: python lena_opencv.py --input Lena.jpg --output results
Dependencies: numpy, opencv-python, matplotlib. No GUI windows required.
"""
from pathlib import Path
import argparse
import cv2
import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt


def main():
    parser=argparse.ArgumentParser()
    parser.add_argument('--input',type=Path,default=Path('Lena.jpg'))
    parser.add_argument('--output',type=Path,default=Path('results'))
    args=parser.parse_args()
    img=cv2.imread(str(args.input))
    if img is None:
        raise FileNotFoundError(args.input.resolve())
    args.output.mkdir(parents=True,exist_ok=True)
    # Normalize size so the documented ROI and template coordinates are reproducible.
    img=cv2.resize(img,(512,512),interpolation=cv2.INTER_AREA)
    gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    def save(name,panels):
        fig,axes=plt.subplots(1,len(panels),figsize=(3.5*len(panels),3.9),squeeze=False)
        for ax,(title,image) in zip(axes.flat,panels):
            ax.imshow(cv2.cvtColor(image,cv2.COLOR_BGR2RGB) if image.ndim==3 else image,cmap='gray',vmin=0,vmax=255)
            ax.set_title(title,fontsize=10);ax.axis('off')
        fig.tight_layout();fig.savefig(args.output/(name+'.jpg'),dpi=140,facecolor='white',pil_kwargs={'quality':90});plt.close(fig)
    roi=img[180:380,200:400].copy()
    annotated=img.copy()
    cv2.rectangle(annotated,(200,180),(399,379),(0,255,255),2)
    cv2.circle(annotated,(300,280),6,(0,0,255),-1)
    cv2.putText(annotated,'ROI: x=200 y=180',(18,35),cv2.FONT_HERSHEY_SIMPLEX,0.7,(0,255,255),2,cv2.LINE_AA)
    save('01-roi',[('Original: 512 x 512',img),('BGR drawing + ROI box',annotated),('img[180:380, 200:400]',roi)])
    matrix=cv2.getRotationMatrix2D((256,256),25,0.85)
    rotated=cv2.warpAffine(img,matrix,(512,512),borderValue=(255,255,255))
    gray_bgr=cv2.cvtColor(gray,cv2.COLOR_GRAY2BGR)
    tinted=np.full_like(img,(255,80,0))
    blended=cv2.addWeighted(img,0.75,tinted,0.25,0)
    save('02-transform',[('Rotate 25 deg, scale 0.85',rotated),('75% image + 25% BGR tint',blended),('75% color + 25% grayscale',cv2.addWeighted(img,0.75,gray_bgr,0.25,0))])
    hsv=cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
    mask=cv2.inRange(hsv,np.array([140,40,40]),np.array([179,255,255]))
    masked=cv2.bitwise_and(img,img,mask=mask)
    save('03-mask',[('Original',img),('HSV mask: H=140..179',mask),('bitwise_and with mask',masked)])
    template=gray[240:300,240:320].copy()
    response=cv2.matchTemplate(gray,template,cv2.TM_CCOEFF_NORMED)
    _,score,_,location=cv2.minMaxLoc(response)
    x,y=location
    result=img.copy();cv2.rectangle(result,(x,y),(x+79,y+59),(0,255,0),2)
    heat=cv2.applyColorMap(cv2.normalize(response,None,0,255,cv2.NORM_MINMAX).astype(np.uint8),cv2.COLORMAP_VIRIDIS)
    save('04-template',[('Template: 80 x 60',template),('Response map (normalized)',heat),(f'Best: ({x}, {y}), score={score:.3f}',result)])
    assert location==(240,240),location
    assert cv2.imwrite(str(args.output/'annotated.png'),annotated)
    assert cv2.imwrite(str(args.output/'mask.png'),mask)
    print(f'ROI={roi.shape}; mask={mask.dtype}; response={response.shape}; best={location}; score={score:.6f}')

if __name__=='__main__':
    main()
