如今的手机,得益于庞大的市场需求和激烈的市场竞争产生了先进的算法,价格相对低廉的手机摄像头拍摄出来的照片质量远远超过于昂贵的工业相机。所以,在某些特定的场合下,你对拍摄速度不讲究 但是对图像质量以及成本十分敏感的话,用手机去替代相机,未尝不是一个很好的思路。
1 编写手机端APP,该app 主要实现以下功能:和外部主机建立tcp连接,接收外部主机命令,打开摄像头,并将图片经过压缩后传输回主机。核心代码一个是网络传输处理的类TcpConnect,一个是控制摄像头的页面 cameraFramement。
class TcpConnect : Runnable {
private var mServerSocket: ServerSocket? = null
private var mClient: Socket? = null
private var callback: Handler.Callback? = null
private var out: BufferedOutputStream? = null
private val SendBufferSize = 16777216
private val SERVER_PORT = 10086
init {
try {
mServerSocket = ServerSocket(SERVER_PORT)
mServerSocket!!.reuseAddress = true
println("建立Socket")
} catch (e: IOException) {
e.printStackTrace()
}
}
fun sendData(data: ByteArray?) {
if (mClient == null || !mClient!!.isConnected) {
return
}
try {
out = BufferedOutputStream(mClient!!.getOutputStream())
if (data != null && data.isNotEmpty()) {
out!!.write(data)
}
} catch (e: IOException) {
Log.e("output", "输入输出异常")
e.printStackTrace()
}
}
@JvmName("setCallback1")
fun setCallback(_callback: Handler.Callback?) {
callback = _callback
}
fun listen() {
while (true) try {
if (mServerSocket == null) {
mServerSocket = ServerSocket(SERVER_PORT)
mServerSocket!!.reuseAddress = true
}
mClient = mServerSocket!!.accept()
mClient?.run {
reuseAddress = true
sendBufferSize = SendBufferSize
}
println("TcpConnect 在监听")
val `in` = BufferedInputStream(mClient?.getInputStream())
val buffer = ByteArray(2)
while (`in`.read(buffer).also { bytesRead = it } != -1) {
val msg = Message()
msg.what = buffer[1].toInt()
callback!!.handleMessage(msg)
}
} catch (e: IOException) {
println("TcpConnect" + e.message)
}
}
class CameraFragment : Handler.Callback {
@SuppressLint("MissingPermission")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
Thread {
tcp=TcpConnect()
tcp.setCallback(this@CameraFragment)
tcp.listen()
}.start()
initializeCamera()
}
private fun initializeCamera() = lifecycleScope.launch(Dispatchers.Main) {
camera = openCamera(cameraManager, args.cameraId, cameraHandler)
val size = characteristics.get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)!!
.getOutputSizes(args.pixelFormat).maxByOrNull { it.height * it.width }!!
imageReader = ImageReader.newInstance(
size.width, size.height, args.pixelFormat, IMAGE_BUFFER_SIZE)
imageReader.setOnImageAvailableListener({
val image = it.acquireNextImage()
val buffer = image.planes[0].buffer;
val len = buffer.remaining()
var outData = ByteArray(len)
buffer.get(outData, 0, len)
imageSendThread.run {
Runnable {
tcp.sendData(outData)
tcp.flush()
buffer.clear()
}.run()
}
image.close();
}, imageReaderHandler)
}
2 主机端应用程序。主要实现 发送控制命令(打开/关闭手机摄像头),接收图像并显示出来。我这里PC端是基于.net core的wpf。
public partial class MainWindow : Window
{
Socket client;
Thread listen;
readonly BitmapImage bmp = new();
byte[] imgData;
public MainWindow()
{
InitializeComponent();
}
private void ConnectApp()
{
client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
client.SendTimeout = 5000;
client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
client.ReceiveBufferSize = 4096 * 4096;
IPAddress myIP = IPAddress.Parse("127.0.0.1");
IPEndPoint EPhost = new IPEndPoint(myIP, 12580);
client.Connect(EPhost);
listen = new Thread(Received) { IsBackground = true };
listen.Start();
}
void Received()
{
while (true)
{
if (client == null)
{
continue;
}
if (!client.Connected || !listening)
{
ShowData(3, "连接已断开,停止监听");
break;
}
try
{
client.Receive(buffer);
.....
}
}
}
文章源自千度号-https://www.taibaowl.com/26032.html
评论