更新
This commit is contained in:
@@ -1,87 +1,87 @@
|
||||
"""实拍会话列表,逐行报告名称字形哈希的置位数,并导出取样带截图。
|
||||
|
||||
用途:定位为什么某些联系人的 256 位名称哈希退化成全零。
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
|
||||
import numpy as np
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
import cv2 # noqa: E402
|
||||
|
||||
from wechat_bot import WeChatBot, _NAME_FP_BYTES # noqa: E402
|
||||
|
||||
OUT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "namehash")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
os.makedirs(OUT, exist_ok=True)
|
||||
bot = WeChatBot()
|
||||
if not bot.connect(activate=False):
|
||||
raise SystemExit("挂载企业微信失败")
|
||||
img = bot.capture_session_list()
|
||||
if img is None:
|
||||
raise SystemExit("截取会话列表失败")
|
||||
cv2.imwrite(os.path.join(OUT, "list.png"), img)
|
||||
scale = max(0.75, float(bot.scale or 1.0))
|
||||
print(f"列表尺寸 {img.shape[1]}x{img.shape[0]} scale={scale}")
|
||||
|
||||
centers = bot._avatar_row_centers(img)
|
||||
print(f"检出 {len(centers)} 行头像,中心={centers}")
|
||||
|
||||
# 名称哈希实际取样的两条带(与 _session_name_fingerprint 保持一致)
|
||||
bands = {
|
||||
"prefix": (60 * scale, 84 * scale, -8 * scale, -2 * scale),
|
||||
"main": (80 * scale, img.shape[1] - 60 * scale, -21 * scale, -2 * scale),
|
||||
}
|
||||
|
||||
for idx, raw_center in enumerate(centers):
|
||||
y_c = bot._avatar_anchor(img, raw_center)
|
||||
name_fp = bot._session_name_fingerprint(img, y_c, row_center=True)
|
||||
avatar_fp = bot._session_fingerprint(img, y_c, row_center=True)
|
||||
bits = int.from_bytes(name_fp or b"", "big").bit_count()
|
||||
head = (avatar_fp or b"")[:8].hex()
|
||||
print(
|
||||
f"行{idx}: 锚点 {raw_center}->{y_c} 名称置位={bits:3d}/256 "
|
||||
f"长度={len(name_fp or b'')} 头像={head}"
|
||||
)
|
||||
for tag, (x1, x2, dy1, dy2) in bands.items():
|
||||
xa, xb = int(max(0, x1)), int(min(img.shape[1], x2))
|
||||
ya, yb = int(max(0, y_c + dy1)), int(min(img.shape[0], y_c + dy2))
|
||||
crop = img[ya:yb, xa:xb]
|
||||
if crop.size:
|
||||
gray = crop[:, :, :3].astype(np.float32).mean(axis=2)
|
||||
background = float(np.median(gray))
|
||||
ink = float((np.abs(gray - background) >= 16.0).mean())
|
||||
print(
|
||||
f" {tag:6s} x[{xa},{xb}) y[{ya},{yb}) "
|
||||
f"底色={background:.0f} 墨迹占比={ink:.3f}"
|
||||
)
|
||||
cv2.imwrite(os.path.join(OUT, f"row{idx}_{tag}.png"), crop)
|
||||
else:
|
||||
print(f" {tag:6s} 取样区为空 x[{xa},{xb}) y[{ya},{yb})")
|
||||
print(f"\n截图已写入 {OUT}")
|
||||
print(f"_NAME_FP_BYTES={_NAME_FP_BYTES}")
|
||||
|
||||
# 不同联系人之间名称哈希的距离下界,决定容差能开到多大
|
||||
print("\n当前列表内不同行的名称哈希距离:")
|
||||
fps = []
|
||||
for idx, raw_center in enumerate(centers):
|
||||
y_c = bot._avatar_anchor(img, raw_center)
|
||||
fps.append((idx, bot._session_name_fingerprint(img, y_c, row_center=True)))
|
||||
worst = 999
|
||||
for i in range(len(fps)):
|
||||
for j in range(i + 1, len(fps)):
|
||||
a, b = fps[i][1], fps[j][1]
|
||||
if len(a) != _NAME_FP_BYTES or len(b) != _NAME_FP_BYTES:
|
||||
continue
|
||||
dist = (int.from_bytes(a, "big") ^ int.from_bytes(b, "big")).bit_count()
|
||||
worst = min(worst, dist)
|
||||
print(f" 行{fps[i][0]} vs 行{fps[j][0]}: {dist}")
|
||||
print(f"不同联系人名称距离下界 = {worst}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
"""实拍会话列表,逐行报告名称字形哈希的置位数,并导出取样带截图。
|
||||
|
||||
用途:定位为什么某些联系人的 256 位名称哈希退化成全零。
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
|
||||
import numpy as np
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
import cv2 # noqa: E402
|
||||
|
||||
from wechat_bot import WeChatBot, _NAME_FP_BYTES # noqa: E402
|
||||
|
||||
OUT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "namehash")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
os.makedirs(OUT, exist_ok=True)
|
||||
bot = WeChatBot()
|
||||
if not bot.connect(activate=False):
|
||||
raise SystemExit("挂载企业微信失败")
|
||||
img = bot.capture_session_list()
|
||||
if img is None:
|
||||
raise SystemExit("截取会话列表失败")
|
||||
cv2.imwrite(os.path.join(OUT, "list.png"), img)
|
||||
scale = max(0.75, float(bot.scale or 1.0))
|
||||
print(f"列表尺寸 {img.shape[1]}x{img.shape[0]} scale={scale}")
|
||||
|
||||
centers = bot._avatar_row_centers(img)
|
||||
print(f"检出 {len(centers)} 行头像,中心={centers}")
|
||||
|
||||
# 名称哈希实际取样的两条带(与 _session_name_fingerprint 保持一致)
|
||||
bands = {
|
||||
"prefix": (60 * scale, 84 * scale, -8 * scale, -2 * scale),
|
||||
"main": (80 * scale, img.shape[1] - 60 * scale, -21 * scale, -2 * scale),
|
||||
}
|
||||
|
||||
for idx, raw_center in enumerate(centers):
|
||||
y_c = bot._avatar_anchor(img, raw_center)
|
||||
name_fp = bot._session_name_fingerprint(img, y_c, row_center=True)
|
||||
avatar_fp = bot._session_fingerprint(img, y_c, row_center=True)
|
||||
bits = int.from_bytes(name_fp or b"", "big").bit_count()
|
||||
head = (avatar_fp or b"")[:8].hex()
|
||||
print(
|
||||
f"行{idx}: 锚点 {raw_center}->{y_c} 名称置位={bits:3d}/256 "
|
||||
f"长度={len(name_fp or b'')} 头像={head}"
|
||||
)
|
||||
for tag, (x1, x2, dy1, dy2) in bands.items():
|
||||
xa, xb = int(max(0, x1)), int(min(img.shape[1], x2))
|
||||
ya, yb = int(max(0, y_c + dy1)), int(min(img.shape[0], y_c + dy2))
|
||||
crop = img[ya:yb, xa:xb]
|
||||
if crop.size:
|
||||
gray = crop[:, :, :3].astype(np.float32).mean(axis=2)
|
||||
background = float(np.median(gray))
|
||||
ink = float((np.abs(gray - background) >= 16.0).mean())
|
||||
print(
|
||||
f" {tag:6s} x[{xa},{xb}) y[{ya},{yb}) "
|
||||
f"底色={background:.0f} 墨迹占比={ink:.3f}"
|
||||
)
|
||||
cv2.imwrite(os.path.join(OUT, f"row{idx}_{tag}.png"), crop)
|
||||
else:
|
||||
print(f" {tag:6s} 取样区为空 x[{xa},{xb}) y[{ya},{yb})")
|
||||
print(f"\n截图已写入 {OUT}")
|
||||
print(f"_NAME_FP_BYTES={_NAME_FP_BYTES}")
|
||||
|
||||
# 不同联系人之间名称哈希的距离下界,决定容差能开到多大
|
||||
print("\n当前列表内不同行的名称哈希距离:")
|
||||
fps = []
|
||||
for idx, raw_center in enumerate(centers):
|
||||
y_c = bot._avatar_anchor(img, raw_center)
|
||||
fps.append((idx, bot._session_name_fingerprint(img, y_c, row_center=True)))
|
||||
worst = 999
|
||||
for i in range(len(fps)):
|
||||
for j in range(i + 1, len(fps)):
|
||||
a, b = fps[i][1], fps[j][1]
|
||||
if len(a) != _NAME_FP_BYTES or len(b) != _NAME_FP_BYTES:
|
||||
continue
|
||||
dist = (int.from_bytes(a, "big") ^ int.from_bytes(b, "big")).bit_count()
|
||||
worst = min(worst, dist)
|
||||
print(f" 行{fps[i][0]} vs 行{fps[j][0]}: {dist}")
|
||||
print(f"不同联系人名称距离下界 = {worst}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user