import cv2, numpy as np
from skimage.morphology import skeletonize

src = "/home/gxs/Desktop/data/2300图像文件测试数据/R4407845900002021120182/R4407845900002021120182_01_01_01_01.bmp"
img = cv2.imread(src, cv2.IMREAD_GRAYSCALE)
imgf = img.astype(np.float32)

# --- continuous ridge signal: Gabor bank (high = periodic dark ridge) ---
resp = np.zeros_like(imgf)
for freq in (0.10, 0.125, 0.15):
    for theta in range(0, 180, 15):
        k = cv2.getGaborKernel((21, 21), 0.55, theta, 1.0/freq, 0.5, 0, ktype=cv2.CV_32F)
        resp = np.maximum(resp, cv2.filter2D(imgf, -1, k))

# normalize per-block to remove illumination bias
B = 64
norm = np.zeros_like(resp)
for by in range(0, img.shape[0], B):
    for bx in range(0, img.shape[1], B):
        blk = resp[by:by+B, bx:bx+B]
        lo, hi = blk.min(), blk.max()
        if hi - lo > 1e-6:
            norm[by:by+B, bx:bx+B] = (blk - lo) / (hi - lo)

# print region
den = cv2.GaussianBlur(img, (5,5), 0)
_, gotsu = cv2.threshold(den, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
pr = (gotsu == 0).astype(np.uint8)
if pr.mean() > 0.5:
    pr = 1 - pr

mask = (norm > 0.50).astype(np.uint8) * pr
k2 = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (2,2))
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, k2)
# small close to bridge tiny grain gaps (2px only, avoids merging)
k3 = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3))
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, k3, iterations=1)
print(f"ridge fraction: {mask.mean():.3f}")
skel = skeletonize(mask > 0)
print(f"skeleton px: {skel.sum()}")
canvas = np.hstack([img, (mask*255).astype(np.uint8), (255*(skel>0)).astype(np.uint8)])
cv2.imwrite('/tmp/fp_norm.png', canvas)
print('saved')
