上一篇文章留下了一个问题,就是如何解决垂直线变斜的问题。
这个问题本来应该从通信上来解决,找出行同步信号,然后在这个信号处换行。
但是实际并不好做,因为hdmi并不是无线通信标准,没有这方面的资料。
因此,我打算用图像处理的方式来解决。即找出原始画面的规律,然后从画面上直观地做一些修改,来改善效果。
我本来考虑过给图形做仿射变换,相当于旋转图像,但是我估计效果不会太好。
后来我想了想,目前的问题无非就是每个行开始处有个offset的问题。我只要把这个offset位置的像素点挪到最开头那个点就行。还有个问题是这个offset对于每一行来说都是在变化的,幸运的是变化的趋势是固定的,比如下一行都比上一行offset大了一个固定的值。这样就很容易搞定了。
当然实际做的时候还会碰到各种各样的细节问题,比如offset后的像素挪到了左侧后,这一行offset前的像素点是不是就直接扔掉了?显然,不能这样,不然每行的右侧都会缺东西。事实上每一行的右侧都是用下一行offset左侧的像素点补上去的。
还有就是如果一下子写不出循环也不要紧,建议先参考我注释里写的那样,想象一种比较特殊的情形,然后把特殊情形的实际的像素点位置等数字写出来,然后从这些像素点之间的关系做一个归纳,找出他们的规律,然后再写循环,就会方便不少。
实际写代码过程中还会碰到各种各样的问题:
比如range(0,10)是从0到9,如果要包含10就需要改为range(0,10+1)。
另外offset如果不停减去一个固定值,可能会小于0,导致某几个取值超过边界,这时候可以想象如果一行的offset位置是0,那下一行的位置可以认为是-1(小于0),也可以认为在屏幕的右侧出现,此时就是行宽-1。也就是说可以把行宽作为周期,在offset小于0时给它补上去。同理,如果offset不停加上一个固定值也可能超出行宽,这时给它减去一个周期(行宽)就行。这就是我在代码56~59行做的事情。如果你不理解你可以把这部分删除,看看程序是否报错,再把对应x,y,offset的变量打印出来,看看为啥这些变量在这个取值时会报错就能理解我为啥要这么写了。
from pylab import *
from rtlsdr import *
import cv2
sdr = RtlSdr()
# configure device
sdr.sample_rate = 1.951047e6
sdr.center_freq = 395.991e6
sdr.gain = 60
# init for opencv
x = 0
y = 0
img = np.zeros((600,600,1), np.uint8)
img_to_show = np.zeros((600,600,1), np.uint8)
coarse_length_of_line = 580
fine_tune_of_offset_variation = -2
height_to_draw = 500
while True:
samples = sdr.read_samples(1024*100) #type(sample) is numpy.complex128
for sample in samples:
mag = np.sqrt( sample.imag * sample.imag + sample.real * sample.real)
value = mag * 255 * 10 #type(value) numpy.float64
img[y, x] = value
img[y, x + 1] = value
img[y, x + 2] = value
img[y, x + 3] = value
img[y, x + 4] = value
img[y, x + 5] = value
img[y, x + 6] = value
img[y, x + 7] = value
img[y, x + 8] = value
img[y, x + 9] = value
x = x + 10
if (x >= coarse_length_of_line):
x = 0
y = y + 1
if (y >= height_to_draw):
y = 0
offset = 0
for j in range(0, height_to_draw):
for i in range(0, coarse_length_of_line - offset + 1): # contains 0 and coarse_length_of_line - offset
img_to_show[j, i] = img[j, i + offset]
for i in range(coarse_length_of_line - offset + 1, coarse_length_of_line + 1):
img_to_show[j, i] = img[j + 1, i + offset - coarse_length_of_line - 1]
offset = offset + fine_tune_of_offset_variation
if (offset < 0):
offset = offset + coarse_length_of_line
elif (offset > coarse_length_of_line):
offset = offset - coarse_length_of_line
'''
img_to_show[0, 0] = img[0, 50]
img_to_show[0, 1] = img[0, 51]
...
img_to_show[0, 530] = img[0, 580]
img_to_show[0, 531] = img[1, 0]
...
img_to_show[0, 580] = img[1, 49]
img_to_show[1, 0] = img[1, 45]
img_to_show[1, 1] = img[1, 46]
...
img_to_show[1, 535] = img[1, 580]
img_to_show[1, 536] = img[2, 0]
...
img_to_show[1, 580] = img[2, 44]
'''
cv2.imshow("HDMI", img)
cv2.imshow("HDMI2", img_to_show)
if(cv2.waitKey(10)==27):
break
sdr.close()
我的程序还是有不少要优化的地方,比如纠正后的画面中间老是会有一条细斜线,如果大家知道为啥可以告诉我。
另外就是如果能找出hdmi的行同步和帧同步信号对无线电的实际影响并用于纠偏就更好了。
本文代码实际效果:
SDR接收HDMI泄漏3 极简代码实现tempestsdr_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1U34y1H7YD