u/LostInGermany4297

Computational frame differential video- live-view best watch full screen on computer

Using normal light field, opening in python OpenCV - live-view USB industrial camera, converting the input to gray-scale, adding green for frame differences. Sample from my brew of Bristle Moss developing well, seem like an Ark for Noah for micro-wild life. objective 10x

u/LostInGermany4297 — 8 hours ago

Computational frame differential image - live-view best watch full screen on computer

Using normal light field, opening in python OpenCV - live-view USB industrial camera, converting the input to gray-scale, adding green for frame differences. I actually wrote this for some bigger protozoa to see water flow but had for my test only my brew of the Bristle Moss, which is still advancing. For now only a demonstration of the incredible speed of Bacteria at 60x - total magnification aprox 1000x on screen.

BTW I have ordered some cheap objectives to see if I can do a demonstration with a cheap setup to have some useful purpose, target is round 500 USD - EUR total

u/LostInGermany4297 — 1 day ago

Red Blood cells Computational Phase Contrast Test (Red/Blue LED)

Another test with the computational phase contrast setup on blood cells

  • Illumination: Single RGB LED chip running only the red and blue channels simultaneously to produce purple light.
  • Objective: 45×
  • Resolution: ~0.24 µm per pixel at the specimen plane
  • Visual Magnification: ≈1100× on screen
  • Image from live-stream USB industrial Camera, no further processing.
  • Python script using OpenCV and running in Idle or cmd.
  • Sample blood smear no cover glass used.
u/LostInGermany4297 — 4 days ago

DIY, Computational Phase Contrast from Red and Blue channel, python OpenCV live-view script Orthotrichum - Bristle Moss (probably)

Illumination with RGB LED color purple. Python script, live-view with manipulating Blue and Red while subtracting green. B and R layer are then aligned.

Chloroplasts are white, cell borders dark in this illumination.

~0.24 µm per pixel at the specimen plane (45× objective; on my screen ≈1100× visual magnification)

u/LostInGermany4297 — 6 days ago

DIY, Computational Phase Contrast from Red and Blue channel, python OpenCV live-view script Cheek Cells again.

Cheek Cells as test.

~0.24 µm per pixel at the specimen plane (45× objective; on my screen ≈1100× visual magnification)

I have been working a bit further on this image one is an average of 3 frames, pic 2 is a single frame. I will post in comments a video showing the speed and focusing

I am using a normal light microscope Olympus CH2 1983 removed the mirror and put in place a RGB LED rechargeble with ir remote for changing colors. This LED has the 3 colors in the chip in a row so blue and red can be illuminated with some off-set. I diffuse it with some paper for the the moment, Python is reading the industrial camera on USB and I run in Idle the live-screen from doing the computation in real time. it is doing about the 25 fps I am capturing.

u/LostInGermany4297 — 7 days ago

An idea and a proof of concept, Computational Phase contrast from Blue and Red on a normal microscope. (Cheek cells)

Cheek Cells as test.

45x magnification contrast obtained with live-view python script as attached.

~0.24 µm per pixel at the specimen plane (45× objective; on my screen ≈1100× visual magnification)

Last Friday i was thinking about how to do phase contrast microscopy on a normal microscope. After reading something about the way to convert the light path, I thought why not do this using only red and blue light by putting this in the light path direct over the light. To make it easy I have written a Python script using the OpenCV capturing the USB camera and showing a live-view. (I will share the script in a later post. After making this I checked if someone did this already and it seems to be called "computational phase contrast microscopy". Apparently the benchmark is to show cheek-cells which I am doing here. This is a simple cheap project allowing a new way to see the micro world. Below a composite of some of the cheek cells

Hardeware: Modified darkfield microscope Ebay 30 Euro - Camera industrial camera 100 Euro.

- I am Interested in similar approaches.

I am using python and OpenCV to connect the USB in a live-view. The below code I run in Idle and has some toggles to make some adjustments and save a screen.

=== CONTROLS ===

ESC - Quit

p - Cycle view: 0=phase, 1=phase+overlay, 2=raw

n - Toggle noise reduction

m - Toggle micrometer scale bar

c - Cycle contrast modes (0=clean, 1=medium, 2=extreme)

w - Toggle soft white background

e - Cycle embossing (0=off, 1=min, 2=med, 3=strong)

s - Save current frame

================

The python code for live-view

```python

import cv2

import numpy as np

from datetime import datetime

# ============================================================

# CAMERA INITIALIZATION

# ============================================================

cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)

cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)

cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)

cap.set(cv2.CAP_PROP_FPS, 30)

if not cap.isOpened():

print("ERROR: Could not open camera on port 0")

exit(1)

# ============================================================

# PARAMETERS

# ============================================================

DOWNSCALE_SIZE = (128, 128)

ALPHA = 0.2

MAX_SHIFT_PER_FRAME = 0.5

USE_CLAHE = True

use_noise_reduction = False

show_scale_bar = False

white_background = False

contrast_mode = 0 # 0=clean, 1=medium, 2=extreme

p_mode = 0 # 0=phase, 1=overlay, 2=raw

# Rolling average buffer

avg_buffer = []

AVG_SIZE = 3

# ============================================================

# STARTUP COMMAND LIST

# ============================================================

print("=== CONTROLS ===")

print("ESC - Quit")

print("p - Cycle view: 0=phase, 1=phase+overlay, 2=raw")

print("n - Toggle noise reduction")

print("m - Toggle micrometer scale bar")

print("c - Cycle contrast modes (0=clean, 1=medium, 2=extreme)")

print("w - Toggle soft white background")

print("s - Save current frame")

print("================")

# ============================================================

# HELPERS

# ============================================================

def phase_correlation_shift(img_ref, img_mov):

ref = img_ref.astype(np.float32)

mov = img_mov.astype(np.float32)

shift, _ = cv2.phaseCorrelate(ref, mov)

dy, dx = shift

return dx, dy

def apply_subpixel_shift(img, dx, dy):

M = np.float32([[1, 0, dx],

[0, 1, dy]])

shifted = cv2.warpAffine(

img, M, (img.shape[1], img.shape[0]),

flags=cv2.INTER_LINEAR,

borderMode=cv2.BORDER_REFLECT

)

return shifted

def create_center_roi(img, fraction=0.5):

h, w = img.shape

cw, ch = int(w * fraction), int(h * fraction)

x0 = (w - cw) // 2

y0 = (h - ch) // 2

return x0, y0, cw, ch

def draw_scale_bar(img, bar_px, bar_um):

if img.ndim == 2:

vis = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)

else:

vis = img.copy()

h, w = vis.shape[:2]

margin = 20

thickness = 2

x1 = margin

y1 = h - margin

x2 = x1 + bar_px

y2 = y1

cv2.line(vis, (x1, y1), (x2, y2), (255, 255, 255), thickness)

cv2.putText(vis, f"{bar_um:.0f} um", (x1, y1 - 8),

cv2.FONT_HERSHEY_SIMPLEX, 0.5,

(255, 255, 255), 1, cv2.LINE_AA)

return vis

# ============================================================

# CONTRAST MODES

# ============================================================

def process_clean(img):

return img

def process_medium(img):

lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)

l, a, b = cv2.split(lab)

clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))

l2 = clahe.apply(l)

lab2 = cv2.merge((l2, a, b))

out = cv2.cvtColor(lab2, cv2.COLOR_LAB2BGR)

blur = cv2.GaussianBlur(out, (0,0), 1.0)

return cv2.addWeighted(out, 1.6, blur, -0.6, 0)

def process_extreme(img):

# Convert to LAB

lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)

l, a, b = cv2.split(lab)

# Strong CLAHE

clahe = cv2.createCLAHE(clipLimit=3.5, tileGridSize=(4,4))

l2 = clahe.apply(l)

# Recombine

lab2 = cv2.merge((l2, a, b))

out = cv2.cvtColor(lab2, cv2.COLOR_LAB2BGR)

# Strong sharpening

blur = cv2.GaussianBlur(out, (0,0), 1.2)

out = cv2.addWeighted(out, 2.2, blur, -1.2, 0)

# Slight blue shift for “Euromex yellow speckle”

b, g, r = cv2.split(out)

M = np.float32([[1, 0, 0.4], [0, 1, 0.4]])

b_shift = cv2.warpAffine(b, M, (b.shape[1], b.shape[0]))

return cv2.merge((b_shift, g, r))

# ============================================================

# SOFT WHITE BACKGROUND

# ============================================================

def clean_background_white(img):

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

bg = cv2.medianBlur(gray, 51)

flat = cv2.subtract(gray, bg)

flat = cv2.normalize(flat, None, 20, 235, cv2.NORM_MINMAX)

inv = 255 - flat

inv = cv2.GaussianBlur(inv, (3, 3), 0)

return cv2.cvtColor(inv, cv2.COLOR_GRAY2BGR)

# ============================================================

# MAIN LOOP

# ============================================================

dx_smooth = 0.0

dy_smooth = 0.0

clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8)) if USE_CLAHE else None

while True:

ret, frame = cap.read()

if not ret:

print("Frame grab failed")

break

blue = frame[:, :, 0]

red = frame[:, :, 2]

x0, y0, cw, ch = create_center_roi(blue, fraction=0.5)

blue_roi = blue[y0:y0+ch, x0:x0+cw]

red_roi = red[y0:y0+ch, x0:x0+cw]

small_blue = cv2.resize(blue_roi, DOWNSCALE_SIZE)

small_red = cv2.resize(red_roi, DOWNSCALE_SIZE)

dx_small, dy_small = phase_correlation_shift(small_blue, small_red)

scale_x = cw / DOWNSCALE_SIZE[0]

scale_y = ch / DOWNSCALE_SIZE[1]

dx = np.clip(dx_small * scale_x, -MAX_SHIFT_PER_FRAME, MAX_SHIFT_PER_FRAME)

dy = np.clip(dy_small * scale_y, -MAX_SHIFT_PER_FRAME, MAX_SHIFT_PER_FRAME)

dx_smooth = (1 - ALPHA) * dx_smooth + ALPHA * dx

dy_smooth = (1 - ALPHA) * dy_smooth + ALPHA * dy

red_aligned = apply_subpixel_shift(red, dx_smooth, dy_smooth)

phase_float = red_aligned.astype(np.float32) - blue.astype(np.float32)

phase_norm = cv2.normalize(phase_float, None, 0, 255, cv2.NORM_MINMAX)

phase = phase_norm.astype(np.uint8)

if USE_CLAHE:

phase = clahe.apply(phase)

if use_noise_reduction:

phase = cv2.bilateralFilter(phase, d=5, sigmaColor=25, sigmaSpace=5)

# ---- p-mode display selection ----

if p_mode == 0:

display_img = cv2.cvtColor(phase, cv2.COLOR_GRAY2BGR)

elif p_mode == 1:

phase_color = cv2.cvtColor(phase, cv2.COLOR_GRAY2BGR)

frame_f = frame.astype(np.float32) / 255.0

phase_f = phase_color.astype(np.float32) / 255.0

blended = cv2.addWeighted(frame_f, 0.7, phase_f, 0.3, 0.0)

display_img = (blended * 255).astype(np.uint8)

else:

display_img = frame.copy()

# ---- scale bar only in phase modes ----

if show_scale_bar and p_mode != 2:

display_img = draw_scale_bar(display_img, 80, 20)

# ---- contrast modes only in phase modes ----

if p_mode in (0, 1):

if contrast_mode == 0:

display_img = process_clean(display_img)

elif contrast_mode == 1:

display_img = process_medium(display_img)

else:

display_img = process_extreme(display_img)

if white_background:

display_img = clean_background_white(display_img)

# ---- rolling 3-frame averaging ----

avg_buffer.append(display_img.astype(np.float32))

if len(avg_buffer) > AVG_SIZE:

avg_buffer.pop(0)

display_img = np.mean(avg_buffer, axis=0).astype(np.uint8)

else:

avg_buffer.clear()

cv2.imshow("Phase Contrast Live", display_img)

key = cv2.waitKey(1)

if key == 27:

break

if key == ord('p'):

p_mode = (p_mode + 1) % 3

print("P-mode:", p_mode, "(0=phase, 1=overlay, 2=raw)")

if key == ord('n'):

use_noise_reduction = not use_noise_reduction

print("Noise reduction:", "ON" if use_noise_reduction else "OFF")

if key == ord('m'):

show_scale_bar = not show_scale_bar

print("Micrometer scale:", "ON" if show_scale_bar else "OFF")

if key == ord('c'):

contrast_mode = (contrast_mode + 1) % 3

print("Contrast mode:", contrast_mode)

if key == ord('w'):

white_background = not white_background

print("White background:", "ON" if white_background else "OFF")

if key == ord('s'):

timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")

filename = f"capture_{timestamp}.png"

cv2.imwrite(filename, display_img)

print(f"Saved: {filename}")

cap.release()

cv2.destroyAllWindows()

```

u/LostInGermany4297 — 9 days ago