Given the scan of a fabric (snippet included here, it could easily be A4 size at 600 dpi) what would be the best method for finding the repetition pattern in the scan?
I have tried:
I am aware of other answers on stackoverflow and other sites (this and this and this but they tend to be a bit too terse for an OpenCV beginner.
I am thinking of eyeballing an area and optimizing via row-by-row and column-by-column comparison of pixels, but I am wondering if there is a another better path.

The image's 2D autocorrelation is a good generic way to find repeating structures, as others have commented. There are some details to doing this effectively:
Python code:
# Copyright 2022 Google LLC.
# SPDX-License-Identifier: Apache-2.0
from PIL import Image
import matplotlib.pyplot as plt
import numpy as np
import scipy.signal
image = np.array(Image.open('texture.jpg').convert('L'), float)
# Window the image.
window_x = np.hanning(image.shape[1])
window_y = np.hanning(image.shape[0])
image *= np.outer(window_y, window_x)
# Transform to frequency domain.
spectrum = np.fft.rfft2(image)
# Partially whiten the spectrum. This tends to make the autocorrelation sharper,
# but it also amplifies noise. The -0.6 exponent is the strength of the
# whitening normalization, where -1.0 would be full normalization and 0.0 would
# be the usual unnormalized autocorrelation.
spectrum *= (1e-12 + np.abs(spectrum))**-0.6
# Exclude some very low frequencies, since these are irrelevant to the texture.
fx = np.arange(spectrum.shape[1])
fy = np.fft.fftshift(np.arange(spectrum.shape[0]) - spectrum.shape[0] // 2)
fx, fy = np.meshgrid(fx, fy)
spectrum[np.sqrt(fx**2 + fy**2) < 10] = 0
# Compute the autocorrelation and inverse transform.
acorr = np.real(np.fft.irfft2(np.abs(spectrum)**2))
plt.figure(figsize=(10, 10))
plt.imshow(acorr, cmap='Blues', vmin=0, vmax=np.percentile(acorr, 99.5))
plt.xlim(0, image.shape[1] / 2)
plt.ylim(0, image.shape[0] / 2)
plt.title('2D autocorrelation', fontsize=18)
plt.xlabel('Horizontal lag (px)', fontsize=15)
plt.ylabel('Vertical lag (px)', fontsize=15)
plt.show()
Output:

The period of the flannel texture is visible at the circled point at 282 px horizontally and 290 px vertically.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With