mirror of https://github.com/Nonannet/imagerec.git
Add existing files
This commit is contained in:
commit
dd0818db86
|
@ -0,0 +1,29 @@
|
||||||
|
#Ensure that openwrt cross-compile environment variables are set prior to calling make:
|
||||||
|
# ~/bin/openwrt.config
|
||||||
|
|
||||||
|
CC=mipsel-openwrt-linux-gcc
|
||||||
|
|
||||||
|
CFLAGS= -std=gnu99
|
||||||
|
|
||||||
|
SOURCES= main.c cmdTcpipClient.c imageRec.c
|
||||||
|
|
||||||
|
TARGET ?= imagerec
|
||||||
|
SRC_DIRS ?= ./src
|
||||||
|
|
||||||
|
SRCS := $(shell find $(SRC_DIRS) -name *.cpp -or -name *.c -or -name *.s)
|
||||||
|
OBJS := $(addsuffix .o,$(basename $(SRCS)))
|
||||||
|
DEPS := $(OBJS:.o=.d)
|
||||||
|
|
||||||
|
INC_DIRS := $(shell find $(SRC_DIRS) -type d)
|
||||||
|
INC_FLAGS := $(addprefix -I,$(INC_DIRS))
|
||||||
|
|
||||||
|
CPPFLAGS ?= $(INC_FLAGS) -MMD -MP
|
||||||
|
|
||||||
|
$(TARGET): $(OBJS)
|
||||||
|
$(CC) $(LDFLAGS) $(OBJS) -o $@ $(LOADLIBES) $(LDLIBS)
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
$(RM) $(TARGET) $(OBJS) $(DEPS)
|
||||||
|
|
||||||
|
-include $(DEPS)
|
|
@ -0,0 +1,92 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|ARM">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>ARM</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|ARM">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>ARM</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|ARM64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>ARM64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|ARM64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>ARM64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|x86">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x86</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x86">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x86</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>{6ad72ab1-e95b-4f4c-89bd-0a3052980eb8}</ProjectGuid>
|
||||||
|
<Keyword>Linux</Keyword>
|
||||||
|
<RootNamespace>ImageRecToolLinux</RootNamespace>
|
||||||
|
<MinimumVisualStudioVersion>15.0</MinimumVisualStudioVersion>
|
||||||
|
<ApplicationType>Linux</ApplicationType>
|
||||||
|
<ApplicationTypeRevision>1.0</ApplicationTypeRevision>
|
||||||
|
<TargetLinuxPlatform>Generic</TargetLinuxPlatform>
|
||||||
|
<LinuxProjectType>{D51BCBC9-82E9-4017-911E-C93873C4EA2B}</LinuxProjectType>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x86'" Label="Configuration">
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'" Label="Configuration">
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings" />
|
||||||
|
<ImportGroup Label="Shared" />
|
||||||
|
<ImportGroup Label="PropertySheets" />
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x86'">
|
||||||
|
<TargetExt>.out</TargetExt>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="cmdTcpipClient.c" />
|
||||||
|
<ClCompile Include="imageRec.c" />
|
||||||
|
<ClCompile Include="main.c" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="cmdTcpipClient.h" />
|
||||||
|
<ClInclude Include="imageRec.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemDefinitionGroup />
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets" />
|
||||||
|
</Project>
|
|
@ -0,0 +1,130 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <memory.h>
|
||||||
|
#ifdef __WIN32__
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <windows.h>
|
||||||
|
#else
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __WIN32__
|
||||||
|
#pragma comment(lib, "Ws2_32.lib")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int lsock;
|
||||||
|
int csock = 0;
|
||||||
|
|
||||||
|
int startSocket(void)
|
||||||
|
{
|
||||||
|
#ifdef __WIN32__
|
||||||
|
WSADATA wsa;
|
||||||
|
return WSAStartup(MAKEWORD(2, 0), &wsa);
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int setupCmdTcpServer(int port)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
int rc;
|
||||||
|
rc = startSocket();
|
||||||
|
|
||||||
|
if (rc != 0)
|
||||||
|
{
|
||||||
|
printf("Fehler: startWinsock, fehler code: %d\n", rc);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lsock = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
|
||||||
|
memset(&addr, 0, sizeof(addr)); // set to 0
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_port = htons((unsigned short)port); // port
|
||||||
|
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||||
|
|
||||||
|
if ((bind(lsock, (struct sockaddr*)& addr, sizeof(addr))) != 0)
|
||||||
|
{
|
||||||
|
printf("socket bind failed...\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("Socket successfully binded..\n");
|
||||||
|
|
||||||
|
if (listen(lsock, 5))
|
||||||
|
{
|
||||||
|
printf("listen failed\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void closeTcpConnection()
|
||||||
|
{
|
||||||
|
char rbuff[1] = { 0 };
|
||||||
|
|
||||||
|
printf("close connection\n");
|
||||||
|
if (csock)
|
||||||
|
{
|
||||||
|
shutdown(csock, SHUT_WR);
|
||||||
|
while (recv(csock, rbuff, 1, 0) > 0);
|
||||||
|
#ifdef __WIN32__
|
||||||
|
closesocket(csock);
|
||||||
|
#else
|
||||||
|
close(csock);
|
||||||
|
#endif
|
||||||
|
csock = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendTcpData(char* data, int lenght)
|
||||||
|
{
|
||||||
|
if (csock)
|
||||||
|
if (send(csock, data, (unsigned short)lenght, MSG_NOSIGNAL) < 0) closeTcpConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
int waitForTcpData(char* cmdData, int lenght)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (csock == 0)
|
||||||
|
{
|
||||||
|
printf("wait for incomming connection\n");
|
||||||
|
|
||||||
|
csock = accept(lsock, NULL, NULL);
|
||||||
|
|
||||||
|
printf("incomming connection\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = recv(csock, cmdData, (unsigned int)lenght, 0);
|
||||||
|
|
||||||
|
if (ret == 0)
|
||||||
|
{
|
||||||
|
printf("socket closed\n");
|
||||||
|
closeTcpConnection();
|
||||||
|
}
|
||||||
|
else if (ret < 0)
|
||||||
|
{
|
||||||
|
printf("socket error\n");
|
||||||
|
csock = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
while (ret < 1);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
src/cmdTcpipClient.o: src/cmdTcpipClient.c
|
|
@ -0,0 +1,4 @@
|
||||||
|
int setupCmdTcpServer(int port);
|
||||||
|
int waitForTcpData(char* cmdData, int lenght);
|
||||||
|
void sendTcpData(char* data, int lenght);
|
||||||
|
void closeTcpConnection();
|
Binary file not shown.
|
@ -0,0 +1,515 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "imageRec.h"
|
||||||
|
|
||||||
|
const short sobelFilterKernel[3][3] = { { 3, 10, 3 }, { 0, 0, 0 }, { -3, -10, -3 } };
|
||||||
|
const imageBuffer gausFilterKernel[5] = { 25, 61, 83, 61, 25 };
|
||||||
|
|
||||||
|
int imageWidth = 0;
|
||||||
|
int imageHight = 0;
|
||||||
|
int imageBufferSize = 0;
|
||||||
|
|
||||||
|
int setImageSize(int width, int hight)
|
||||||
|
{
|
||||||
|
imageWidth = width;
|
||||||
|
imageHight = hight;
|
||||||
|
imageBufferSize = width * hight;
|
||||||
|
|
||||||
|
return imageBufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void normalizeImage(imageBuffer* srcImage, imageBuffer* dstImage)
|
||||||
|
{
|
||||||
|
int min = 0xFFFF;
|
||||||
|
int max = 0;
|
||||||
|
unsigned int factor;
|
||||||
|
|
||||||
|
for (int i = 0; i < imageBufferSize; i++)
|
||||||
|
{
|
||||||
|
if (srcImage[i] < min) min = srcImage[i];
|
||||||
|
if (srcImage[i] > max) max = srcImage[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
factor = (1 << 30) / (max - min + 1);
|
||||||
|
|
||||||
|
for (int i = 0; i < imageBufferSize; i++)
|
||||||
|
{
|
||||||
|
dstImage[i] = (imageBuffer)((srcImage[i] - min) * factor / (1<<14));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void gausFilter(imageBuffer * image, imageBuffer * helperImage)
|
||||||
|
{
|
||||||
|
int n = sizeof(gausFilterKernel) / sizeof(gausFilterKernel[0]);
|
||||||
|
int acc;
|
||||||
|
int acck = 0;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
for (int y = 0; y < imageHight; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < imageWidth; x++)
|
||||||
|
{
|
||||||
|
acc = 0;
|
||||||
|
acck = 0;
|
||||||
|
|
||||||
|
for (int j = 0; j < n; j++)
|
||||||
|
{
|
||||||
|
int pos = x + j - n / 2;
|
||||||
|
|
||||||
|
if (pos >= 0 && pos < imageWidth)
|
||||||
|
{
|
||||||
|
acc += image[i + j - n / 2] * gausFilterKernel[j];
|
||||||
|
acck += gausFilterKernel[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
helperImage[i] = (unsigned short)(acc / acck);
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
for (int y = 0; y < imageHight; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < imageWidth; x++)
|
||||||
|
{
|
||||||
|
acc = 0;
|
||||||
|
acck = 0;
|
||||||
|
|
||||||
|
for (int j = 0; j < n; j++)
|
||||||
|
{
|
||||||
|
int pos = y + j - n / 2;
|
||||||
|
|
||||||
|
if (pos >= 0 && pos < imageHight)
|
||||||
|
{
|
||||||
|
acc += helperImage[i + (j - n / 2) * imageWidth] * gausFilterKernel[j];
|
||||||
|
acck += gausFilterKernel[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
image[i] = (unsigned short)(acc / acck);
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int getX(imageBuffer combinedXy)
|
||||||
|
{
|
||||||
|
return (combinedXy & 0xFF) - 0x80;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getY(imageBuffer combinedXy)
|
||||||
|
{
|
||||||
|
return (combinedXy / 0x100) - 0x80;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sobelFilter(imageBuffer * srcImage, imageBuffer * dstImage)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
for (int y = 0; y < imageHight; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < imageWidth; x++)
|
||||||
|
{
|
||||||
|
int dx = 0;
|
||||||
|
int dy = 0;
|
||||||
|
|
||||||
|
if (x > 0 && x < imageWidth - 1 && y > 0 && y < imageHight - 1)
|
||||||
|
{
|
||||||
|
for (int ix = 0; ix < 3; ix++)
|
||||||
|
{
|
||||||
|
for (int iy = 0; iy < 3; iy++)
|
||||||
|
{
|
||||||
|
int srcVal = srcImage[(x + ix - 1) + (y + iy - 1) * imageWidth];
|
||||||
|
|
||||||
|
dx += srcVal * sobelFilterKernel[ix][iy];
|
||||||
|
dy += srcVal * sobelFilterKernel[iy][ix];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dx /= 0x800;
|
||||||
|
dy /= 0x800;
|
||||||
|
|
||||||
|
if (dx > 127) dx = 127;
|
||||||
|
if (dx < -128) dx = -128;
|
||||||
|
if (dy > 127) dy = 127;
|
||||||
|
if (dy < -128) dy = -128;
|
||||||
|
|
||||||
|
//dstImage[i] = combineXy(dx,dy);
|
||||||
|
dstImage[i] = (unsigned short)(dx + 0x80 + (dy + 0x80) * 0x100);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dstImage[i] = 0x8080;
|
||||||
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int getSlope(imageBuffer value)
|
||||||
|
{
|
||||||
|
int dy = (value / 0x100) - 0x80;
|
||||||
|
int dx = (value & 0xFF) - 0x80;
|
||||||
|
|
||||||
|
return (dx * dx + dy * dy);
|
||||||
|
}
|
||||||
|
|
||||||
|
//srcImage must be a result from sobelFilter
|
||||||
|
void nonMaximumSuppression(imageBuffer * srcImage, imageBuffer * dstImage, int minSlope)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
int slope;
|
||||||
|
|
||||||
|
for (int y = 0; y < imageHight; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < imageWidth; x++)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (x > 0 && x < imageWidth - 1 && y > 0 && y < imageHight - 1)
|
||||||
|
{
|
||||||
|
slope = getSlope(srcImage[i]);
|
||||||
|
|
||||||
|
if (slope < minSlope)
|
||||||
|
{
|
||||||
|
dstImage[i] = 0x8080;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
if (getSlope(srcImage[i - 1 - imageWidth]) > slope) count++;
|
||||||
|
if (getSlope(srcImage[i - 0 - imageWidth]) > slope) count++;
|
||||||
|
if (getSlope(srcImage[i + 1 - imageWidth]) > slope) count++;
|
||||||
|
if (getSlope(srcImage[i - 1]) > slope) count++;
|
||||||
|
if (getSlope(srcImage[i + 1]) > slope) count++;
|
||||||
|
if (getSlope(srcImage[i - 1 + imageWidth]) > slope) count++;
|
||||||
|
if (getSlope(srcImage[i - 0 + imageWidth]) > slope) count++;
|
||||||
|
if (getSlope(srcImage[i + 1 + imageWidth]) > slope) count++;
|
||||||
|
|
||||||
|
if (count > 2)
|
||||||
|
dstImage[i] = 0x8080;
|
||||||
|
else
|
||||||
|
dstImage[i] = srcImage[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dstImage[i] = 0x8080;
|
||||||
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*void drawLine(imageBuffer* dstImage, int x0, int y0, int x1, int y1)
|
||||||
|
{
|
||||||
|
int x = x0;
|
||||||
|
int y = y0;
|
||||||
|
int dx = x1 - x0;
|
||||||
|
int dy = y1 - y0;
|
||||||
|
int err = dx + dy, e2; // error value e_xy
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
dstImage[y * IMAGE_WIDTH + x] += 1;// 64 + cr;
|
||||||
|
if (x == x1 && y == y1) break;
|
||||||
|
e2 = 2 * err;
|
||||||
|
if (e2 > dy) { err += dy; x++; }
|
||||||
|
if (e2 < dx) { err += dx; y++; }
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
void houghTransformCircles(imageBuffer * srcImage, imageBuffer * dstImage)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
int xslope, yslope;
|
||||||
|
|
||||||
|
for (int y = 0; y < imageHight; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < imageWidth; x++)
|
||||||
|
{
|
||||||
|
if (srcImage[i] != 0x8080)
|
||||||
|
{
|
||||||
|
xslope = getX(srcImage[i]);
|
||||||
|
yslope = getY(srcImage[i]);
|
||||||
|
|
||||||
|
if (xslope * xslope > yslope * yslope)
|
||||||
|
{
|
||||||
|
for (int xi = 0; xi < imageWidth; xi++)
|
||||||
|
{
|
||||||
|
int yi = (xi - x) * yslope / xslope + y;
|
||||||
|
|
||||||
|
if (yi > 0 && yi < imageHight)
|
||||||
|
dstImage[yi * imageWidth + xi]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int yi = 0; yi < imageHight; yi++)
|
||||||
|
{
|
||||||
|
int xi = (yi - y) * xslope / yslope + x;
|
||||||
|
|
||||||
|
if (xi > 0 && xi < imageWidth)
|
||||||
|
dstImage[yi * imageWidth + xi]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void intenerlal_houghTransformLines(imageBuffer * srcImage, imageBuffer * dstImage, int filter)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
const int cx = imageWidth / 2;
|
||||||
|
const int cy = imageHight / 2;
|
||||||
|
|
||||||
|
for (int y = 0; y < imageHight; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < imageWidth; x++)
|
||||||
|
{
|
||||||
|
if (srcImage[i] != 0x8080)
|
||||||
|
{
|
||||||
|
int xslope = getX(srcImage[i]);
|
||||||
|
int yslope = getY(srcImage[i]);
|
||||||
|
int xslope2 = xslope * xslope;
|
||||||
|
int yslope2 = yslope * yslope;
|
||||||
|
|
||||||
|
if (filter == 0 || (filter == 1 && yslope2 > xslope2) || (filter == 2 && yslope2 < xslope2))
|
||||||
|
{
|
||||||
|
|
||||||
|
int inter = ((x - cx) * xslope + (y - cy) * yslope) * 0x100 / (xslope2 + yslope2);
|
||||||
|
int htx = cx + inter * xslope / 0x100;
|
||||||
|
int hty = cy + inter * yslope / 0x100;
|
||||||
|
|
||||||
|
if (htx > 0 && htx < imageWidth && hty > 0 && hty < imageHight && dstImage[hty * imageWidth + htx] < 0xFFFF)
|
||||||
|
dstImage[hty * imageWidth + htx] ++;
|
||||||
|
|
||||||
|
//std::cout << htx << " " << hty << " - " << xslope << " " << yslope << " " << ".\n";
|
||||||
|
//printf("%i %i %i %i\n", htx, hty, xslope, yslope);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void houghTransformLines(imageBuffer* srcImage, imageBuffer* dstImage)
|
||||||
|
{
|
||||||
|
intenerlal_houghTransformLines(srcImage, dstImage, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void houghTransformVerticalLines(imageBuffer* srcImage, imageBuffer* dstImage)
|
||||||
|
{
|
||||||
|
intenerlal_houghTransformLines(srcImage, dstImage, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void houghTransformHorizontalLines(imageBuffer* srcImage, imageBuffer* dstImage)
|
||||||
|
{
|
||||||
|
intenerlal_houghTransformLines(srcImage, dstImage, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int usqrt4(int val) {
|
||||||
|
int a, b;
|
||||||
|
|
||||||
|
a = 256; // starting point is relatively unimportant
|
||||||
|
|
||||||
|
b = val / a; a = (a + b) / 2;
|
||||||
|
b = val / a; a = (a + b) / 2;
|
||||||
|
b = val / a; a = (a + b) / 2;
|
||||||
|
b = val / a; a = (a + b) / 2;
|
||||||
|
b = val / a; a = (a + b) / 2;
|
||||||
|
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void houghTransformMiniscus(imageBuffer * srcImage, imageBuffer * dstImage)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
for (int y = 0; y < imageHight; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < imageWidth; x++)
|
||||||
|
{
|
||||||
|
if (srcImage[i] != 0)
|
||||||
|
{
|
||||||
|
int xslope = getX(srcImage[i]);
|
||||||
|
int yslope = getY(srcImage[i]);
|
||||||
|
|
||||||
|
if (xslope != 0)
|
||||||
|
{
|
||||||
|
int preCalc = 0x1000 * yslope / xslope;
|
||||||
|
|
||||||
|
|
||||||
|
for (int htx = 0; htx < imageWidth; htx++)
|
||||||
|
{
|
||||||
|
int dx = htx - x;
|
||||||
|
//int dy = dx * yslope / xslope;
|
||||||
|
int dy = dx * preCalc / 0x1000;
|
||||||
|
|
||||||
|
if (dx != 0)
|
||||||
|
{
|
||||||
|
int r = usqrt4(dx * dx + dy * dy);
|
||||||
|
//int r = sqrt(dx * dx + dy * dy);
|
||||||
|
|
||||||
|
int hty = y + dy - r;
|
||||||
|
|
||||||
|
if (hty >= 0 && hty < imageHight)
|
||||||
|
dstImage[hty * imageWidth + htx] ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void findMaxima(imageBuffer* srcImage, imageBuffer* dstImage, int threshold, int minDistance)
|
||||||
|
{
|
||||||
|
int ws2 = minDistance / 2;
|
||||||
|
int maxVal;
|
||||||
|
int maxInd;
|
||||||
|
|
||||||
|
for (int i = 0; i < imageBufferSize; i++)
|
||||||
|
{
|
||||||
|
dstImage[i] = srcImage[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int y = ws2; y < imageHight; y += ws2)
|
||||||
|
{
|
||||||
|
for (int x = ws2; x < imageWidth; x += ws2)
|
||||||
|
{
|
||||||
|
maxVal = threshold;
|
||||||
|
maxInd = -1;
|
||||||
|
|
||||||
|
for (int ix = -ws2; ix < ws2; ix++)
|
||||||
|
{
|
||||||
|
for (int iy = -ws2; iy < ws2; iy++)
|
||||||
|
{
|
||||||
|
int i = (x + ix) + (y + iy) * imageWidth;
|
||||||
|
|
||||||
|
if (srcImage[i] > maxVal)
|
||||||
|
{
|
||||||
|
maxInd = i;
|
||||||
|
maxVal = srcImage[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int ix = -ws2; ix < ws2; ix++)
|
||||||
|
{
|
||||||
|
for (int iy = -ws2; iy < ws2; iy++)
|
||||||
|
{
|
||||||
|
int i = (x + ix) + (y + iy) * imageWidth;
|
||||||
|
if (i != maxInd)
|
||||||
|
dstImage[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bubbleSort(struct pixel_list* array, int length)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
struct pixel_list tmp;
|
||||||
|
|
||||||
|
for (i = 1; i < length; i++)
|
||||||
|
{
|
||||||
|
for (j = 0; j < length - i; j++)
|
||||||
|
{
|
||||||
|
if (array[j].value[4] < array[j + 1].value[4])
|
||||||
|
{
|
||||||
|
tmp = array[j];
|
||||||
|
array[j] = array[j + 1];
|
||||||
|
array[j + 1] = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int getPixelList(imageBuffer* primImage, imageBuffer* secImage, struct pixel_list* list, int listLenght)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
int j = 0;
|
||||||
|
|
||||||
|
for (int y = 1; y < imageHight - 1; y++)
|
||||||
|
{
|
||||||
|
for (int x = 1; x < imageWidth - 1; x++)
|
||||||
|
{
|
||||||
|
i = x + y * imageWidth;
|
||||||
|
|
||||||
|
if (primImage[i] != 0 && j < listLenght)
|
||||||
|
{
|
||||||
|
list[j].value[0] = secImage[x + (y - 1) * imageWidth - 1];
|
||||||
|
list[j].value[1] = secImage[x + (y - 1) * imageWidth];
|
||||||
|
list[j].value[2] = secImage[x + (y - 1) * imageWidth + 1];
|
||||||
|
|
||||||
|
list[j].value[3] = secImage[i - 1];
|
||||||
|
list[j].value[4] = secImage[i];
|
||||||
|
list[j].value[5] = secImage[i + 1];
|
||||||
|
|
||||||
|
list[j].value[6] = secImage[x + (y + 1) * imageWidth - 1];
|
||||||
|
list[j].value[7] = secImage[x + (y + 1) * imageWidth];
|
||||||
|
list[j].value[8] = secImage[x + (y + 1) * imageWidth + 1];
|
||||||
|
|
||||||
|
list[j].x = x;
|
||||||
|
list[j].y = y;
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bubbleSort(list, listLenght);
|
||||||
|
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
|
void convertToSlope(imageBuffer* srcImage, imageBuffer* dstImage)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < imageBufferSize; i++)
|
||||||
|
{
|
||||||
|
dstImage[i] = (unsigned short)getSlope(srcImage[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void binarize(imageBuffer * srcImage, imageBuffer * dstImage, int threshold)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < imageBufferSize; i++)
|
||||||
|
{
|
||||||
|
dstImage[i] = (srcImage[i] > threshold) ? 0xFFFF : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearBufferArea(imageBuffer * dstImage, int startLine, int endLine)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < imageBufferSize; i++)
|
||||||
|
{
|
||||||
|
if (i / imageWidth >= startLine && i / imageWidth < endLine)
|
||||||
|
dstImage[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearBuffer(imageBuffer* dstImage)
|
||||||
|
{
|
||||||
|
clearBufferArea(dstImage, 0, imageHight);
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
src/imageRec.o: src/imageRec.c src/imageRec.h
|
||||||
|
|
||||||
|
src/imageRec.h:
|
|
@ -0,0 +1,43 @@
|
||||||
|
|
||||||
|
#define RADIUS_VAL 500
|
||||||
|
|
||||||
|
typedef unsigned short imageBuffer;
|
||||||
|
typedef int bool;
|
||||||
|
|
||||||
|
struct pixel_list {
|
||||||
|
imageBuffer value[9];
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
};
|
||||||
|
|
||||||
|
int setImageSize(int width, int hight);
|
||||||
|
|
||||||
|
void normalizeImage(imageBuffer* srcImage, imageBuffer* dstImage);
|
||||||
|
|
||||||
|
void gausFilter(imageBuffer* image, imageBuffer* helperImage);
|
||||||
|
|
||||||
|
void sobelFilter(imageBuffer* srcImage, imageBuffer* dstImage);
|
||||||
|
|
||||||
|
void nonMaximumSuppression(imageBuffer* srcImage, imageBuffer* dstImage, int minSlope);
|
||||||
|
|
||||||
|
void houghTransformCircles(imageBuffer* srcImage, imageBuffer* dstImage);
|
||||||
|
|
||||||
|
void houghTransformLines(imageBuffer* srcImage, imageBuffer* dstImage);
|
||||||
|
|
||||||
|
void houghTransformVerticalLines(imageBuffer* srcImage, imageBuffer* dstImage);
|
||||||
|
|
||||||
|
void houghTransformHorizontalLines(imageBuffer* srcImage, imageBuffer* dstImage);
|
||||||
|
|
||||||
|
void houghTransformMiniscus(imageBuffer* srcImage, imageBuffer* dstImage);
|
||||||
|
|
||||||
|
void findMaxima(imageBuffer* srcImage, imageBuffer* dstImage, int threshold, int minDistance);
|
||||||
|
|
||||||
|
int getPixelList(imageBuffer* primImage, imageBuffer* secImage, struct pixel_list* list, int listLenght);
|
||||||
|
|
||||||
|
void convertToSlope(imageBuffer* srcImage, imageBuffer* dstImage);
|
||||||
|
|
||||||
|
void binarize(imageBuffer* srcImage, imageBuffer* dstImage, int threshold);
|
||||||
|
|
||||||
|
void clearBufferArea(imageBuffer* dstImage, int startLine, int endLine);
|
||||||
|
|
||||||
|
void clearBuffer(imageBuffer* dstImage);
|
Binary file not shown.
|
@ -0,0 +1,681 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <memory.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <linux/videodev2.h>
|
||||||
|
#include "imageRec.h"
|
||||||
|
#include "cmdTcpipClient.h"
|
||||||
|
|
||||||
|
imageBuffer* buffers[3];
|
||||||
|
struct pixel_list maxima[32];
|
||||||
|
|
||||||
|
unsigned char* buffer;
|
||||||
|
int useTcpIp = 0;
|
||||||
|
int silent = 0;
|
||||||
|
int tcpsilent = 0;
|
||||||
|
|
||||||
|
static int xioctl(int fd, int request, void* arg)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
|
||||||
|
do r = ioctl(fd, (unsigned long)request, arg);
|
||||||
|
while (-1 == r && EINTR == errno);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
int configImageFormat(int fd, struct v4l2_cropcap *cropcap, unsigned int camWidth, unsigned int camHight)
|
||||||
|
{
|
||||||
|
struct v4l2_capability caps = {};
|
||||||
|
|
||||||
|
if (-1 == xioctl(fd, VIDIOC_QUERYCAP, &caps))
|
||||||
|
{
|
||||||
|
perror("Querying capabilities failed");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!silent) printf("Driver caps:\n"
|
||||||
|
" Driver: \"%s\"\n"
|
||||||
|
" Card: \"%s\"\n"
|
||||||
|
" Bus: \"%s\"\n"
|
||||||
|
" Version: %d.%d\n"
|
||||||
|
" Capabilities: %08x\n",
|
||||||
|
caps.driver, caps.card, caps.bus_info, (caps.version >> 16) && 0xff,
|
||||||
|
(caps.version >> 24) && 0xff, caps.capabilities);
|
||||||
|
|
||||||
|
cropcap->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
|
||||||
|
if (-1 == xioctl(fd, VIDIOC_CROPCAP, cropcap))
|
||||||
|
{
|
||||||
|
perror("Querying cropping capabilities failed");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int formatIsSupported = 0;
|
||||||
|
|
||||||
|
struct v4l2_fmtdesc fmtdesc = { 0 };
|
||||||
|
|
||||||
|
fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
|
||||||
|
char fourcc[5] = { 0 };
|
||||||
|
char c, e;
|
||||||
|
|
||||||
|
while (0 == xioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc))
|
||||||
|
{
|
||||||
|
strncpy(fourcc, (char*)& fmtdesc.pixelformat, 4);
|
||||||
|
|
||||||
|
if (fmtdesc.pixelformat == V4L2_PIX_FMT_YUYV)
|
||||||
|
formatIsSupported = 1;
|
||||||
|
|
||||||
|
c = fmtdesc.flags & 1 ? 'C' : ' ';
|
||||||
|
e = fmtdesc.flags & 2 ? 'E' : ' ';
|
||||||
|
if (!silent) printf(" %s: %c%c %s\n", fourcc, c, e, fmtdesc.description);
|
||||||
|
fmtdesc.index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!formatIsSupported)
|
||||||
|
{
|
||||||
|
perror("Pixel format is not supported\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct v4l2_format fmt = { 0 };
|
||||||
|
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
fmt.fmt.pix.width = camWidth;
|
||||||
|
fmt.fmt.pix.height = camHight;
|
||||||
|
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
|
||||||
|
fmt.fmt.pix.field = V4L2_FIELD_NONE;
|
||||||
|
|
||||||
|
if (!silent) printf("Requested camera settings:\n"
|
||||||
|
" Width: %d\n"
|
||||||
|
" Height: %d\n"
|
||||||
|
" Pixel format: %s\n",
|
||||||
|
fmt.fmt.pix.width,
|
||||||
|
fmt.fmt.pix.height,
|
||||||
|
fourcc);
|
||||||
|
|
||||||
|
if (-1 == xioctl(fd, VIDIOC_S_FMT, &fmt))
|
||||||
|
{
|
||||||
|
perror("Setting pixel format failed");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy(fourcc, (char*)& fmt.fmt.pix.pixelformat, 4);
|
||||||
|
|
||||||
|
if (!silent) printf("Selected camera settings:\n"
|
||||||
|
" Width: %d\n"
|
||||||
|
" Height: %d\n"
|
||||||
|
" Pixel format: %s\n",
|
||||||
|
fmt.fmt.pix.width,
|
||||||
|
fmt.fmt.pix.height,
|
||||||
|
fourcc);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int initMmap(int fd)
|
||||||
|
{
|
||||||
|
struct v4l2_requestbuffers req = { 0 };
|
||||||
|
req.count = 1;
|
||||||
|
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
req.memory = V4L2_MEMORY_MMAP;
|
||||||
|
|
||||||
|
if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req))
|
||||||
|
{
|
||||||
|
perror("Requesting buffer failed (initMmap)");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct v4l2_buffer buf = { 0 };
|
||||||
|
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
buf.memory = V4L2_MEMORY_MMAP;
|
||||||
|
buf.index = 0;
|
||||||
|
if (-1 == xioctl(fd, VIDIOC_QUERYBUF, &buf))
|
||||||
|
{
|
||||||
|
perror("Querying buffer failed (initMmap)");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int captureImage(int fd, imageBuffer* destBuffer, unsigned int targetBufferSize)
|
||||||
|
{
|
||||||
|
unsigned int buffSize;
|
||||||
|
|
||||||
|
struct v4l2_buffer buf = { 0 };
|
||||||
|
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
buf.memory = V4L2_MEMORY_MMAP;
|
||||||
|
buf.index = 0;
|
||||||
|
if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))
|
||||||
|
{
|
||||||
|
perror("Query buffer failed (captureImage)");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-1 == xioctl(fd, VIDIOC_STREAMON, &buf.type))
|
||||||
|
{
|
||||||
|
perror("Query start Capture failed");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd_set fds;
|
||||||
|
FD_ZERO(&fds);
|
||||||
|
FD_SET(fd, &fds);
|
||||||
|
struct timeval tv = { 0 };
|
||||||
|
tv.tv_sec = 2;
|
||||||
|
int r = select(fd + 1, &fds, NULL, NULL, &tv);
|
||||||
|
if (-1 == r)
|
||||||
|
{
|
||||||
|
perror("Waiting for frame timed out");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf))
|
||||||
|
{
|
||||||
|
perror("Retrieving frame failed");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf.bytesused / 2 > targetBufferSize)
|
||||||
|
buffSize = targetBufferSize;
|
||||||
|
else
|
||||||
|
buffSize = buf.bytesused / 2;
|
||||||
|
|
||||||
|
//Extract 8 Bit monocrome Y data from YUYV
|
||||||
|
for (int i = 0; i < buffSize; i++)
|
||||||
|
destBuffer[i] = (imageBuffer)buffer[i * 2] * 0x100;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void printOut(char text[])
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
if (useTcpIp && !tcpsilent)
|
||||||
|
{
|
||||||
|
while (text[i] != 0) i++;
|
||||||
|
sendTcpData((char*)text, i);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!silent) printf("%s", text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void printOutChar(char character)
|
||||||
|
{
|
||||||
|
if (useTcpIp)
|
||||||
|
sendTcpData(&character, 1);
|
||||||
|
else
|
||||||
|
printf("%c", character);
|
||||||
|
}
|
||||||
|
|
||||||
|
void numberToString(int number, int divPos) {
|
||||||
|
int i = 10000;
|
||||||
|
int dCount;
|
||||||
|
int tempVal;
|
||||||
|
char divVal;
|
||||||
|
|
||||||
|
if (number < 0)
|
||||||
|
{
|
||||||
|
printOutChar('-');
|
||||||
|
number *= -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (number)
|
||||||
|
{
|
||||||
|
dCount = 5 - divPos;
|
||||||
|
tempVal = number;
|
||||||
|
while (i)
|
||||||
|
{
|
||||||
|
if (number >= i)
|
||||||
|
{
|
||||||
|
divVal = (char)(tempVal / i);
|
||||||
|
printOutChar(divVal + 48);
|
||||||
|
tempVal -= divVal * i;
|
||||||
|
}
|
||||||
|
else if (dCount < 2)
|
||||||
|
{
|
||||||
|
printOutChar('0');
|
||||||
|
}
|
||||||
|
|
||||||
|
i /= 10;
|
||||||
|
dCount -= 1;
|
||||||
|
if (!dCount && i) printOutChar('.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printOutChar('0');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int write16BitTiff(unsigned short* imageData, unsigned int width, unsigned int height, char* filePath)
|
||||||
|
{
|
||||||
|
FILE* f;
|
||||||
|
|
||||||
|
const unsigned char ofst = 0x86; //134=4+4+2+10*12+4
|
||||||
|
|
||||||
|
unsigned char iwlo = (unsigned char)(width & 0xFF);
|
||||||
|
unsigned char iwhi = (unsigned char)(width >> 8);
|
||||||
|
unsigned char ihlo = (unsigned char)(height & 0xFF);
|
||||||
|
unsigned char ihhi = (unsigned char)(height >> 8);
|
||||||
|
|
||||||
|
unsigned int imagePixels = width * height;
|
||||||
|
unsigned int imageBytes = imagePixels * 2;
|
||||||
|
unsigned char iblo = (unsigned char)(imageBytes & 0xFF);
|
||||||
|
unsigned char ibhi = (unsigned char)((imageBytes >> 8) & 0xFF);
|
||||||
|
unsigned char ibvh = (unsigned char)(imageBytes >> 16);
|
||||||
|
|
||||||
|
unsigned char file_header[] =
|
||||||
|
{
|
||||||
|
'I', 'I', 42, 0, // Little endian magic number
|
||||||
|
0x08, 0x00, 0x00, 0x00, // IFD header at byte 8
|
||||||
|
0x0A, 0x00, // 10 IFD tags
|
||||||
|
0xfe, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //TIFFTAG_SUBFILETYPE = 0
|
||||||
|
0x00, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, iwlo, iwhi, 0x00, 0x00, //TIFFTAG_IMAGEWIDTH = *
|
||||||
|
0x01, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, ihlo, ihhi, 0x00, 0x00, //TIFFTAG_IMAGELENGTH = *
|
||||||
|
0x02, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, //BITS_PER_SAMPLE = 16
|
||||||
|
0x03, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, //TIFFTAG_COMPRESSION = 1 (Non)
|
||||||
|
0x06, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, //TIFFTAG_PHOTOMETRIC = 1 (BlackIsZero)
|
||||||
|
0x11, 0x01, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, ofst, 0x00, 0x00, 0x00, //TIFFTAG_STRIPOFFSETS (image data address)
|
||||||
|
0x12, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, //TIFFTAG_ORIENTATION = 1 (start top left)
|
||||||
|
0x15, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, //TIFFTAG_SAMPLESPERPIXEL = 1
|
||||||
|
0x17, 0x01, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, iblo, ibhi, ibvh, 0x00, //TIFFTAG_STRIPBYTECOUNTS = 1
|
||||||
|
0x00, 0x00, 0x00, 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
f = fopen(filePath, "wb");
|
||||||
|
|
||||||
|
if (f > 0)
|
||||||
|
{
|
||||||
|
fwrite(file_header, 1, sizeof(file_header), f);
|
||||||
|
fwrite(imageData, 2, imagePixels, f);
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (f > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
int exitFlag = 0;
|
||||||
|
char buff[1];
|
||||||
|
int cbuff = 0;
|
||||||
|
int nbuff = 0;
|
||||||
|
int itemCount = 0;
|
||||||
|
int port = 0;
|
||||||
|
char* deviceName = "/dev/video0";
|
||||||
|
char* filePath = "out.tif";
|
||||||
|
imageBuffer* tmpib;
|
||||||
|
const int buffCount = 3;
|
||||||
|
char* pEnd = 0;
|
||||||
|
unsigned int buffSize;
|
||||||
|
unsigned int camWidth = 640;
|
||||||
|
unsigned int camHeight = 480;
|
||||||
|
int maxNumb = 32;
|
||||||
|
int maxMaxNumb = sizeof(maxima) / sizeof(struct pixel_list);
|
||||||
|
char* commandStr = "";
|
||||||
|
int i = 0;
|
||||||
|
int j;
|
||||||
|
int fnIncrPos = -1;
|
||||||
|
int fnIncr = 0;
|
||||||
|
|
||||||
|
while(i < argc)
|
||||||
|
{
|
||||||
|
if (*argv[i] == '-')
|
||||||
|
{
|
||||||
|
switch (*(argv[i] + 1))
|
||||||
|
{
|
||||||
|
case 'p':
|
||||||
|
pEnd = 0;
|
||||||
|
i++;
|
||||||
|
if (*commandStr)
|
||||||
|
printf("Option -p is skiped because -c is specified\n");
|
||||||
|
else
|
||||||
|
if (i < argc) port = strtol(argv[i], &pEnd, 10);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'c':
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if (port)
|
||||||
|
printf("Option -c is skiped because -p is specified\n");
|
||||||
|
else
|
||||||
|
if (i < argc) commandStr = argv[i];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'd':
|
||||||
|
i++;
|
||||||
|
if (i < argc)
|
||||||
|
deviceName = argv[i];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'f':
|
||||||
|
i++;
|
||||||
|
if (i < argc)
|
||||||
|
{
|
||||||
|
j = 0;
|
||||||
|
filePath = argv[i];
|
||||||
|
while (filePath[j] != 0)
|
||||||
|
{
|
||||||
|
if (filePath[j] == '#') fnIncrPos = j;
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'r':
|
||||||
|
i++;
|
||||||
|
if (i < argc)
|
||||||
|
{
|
||||||
|
pEnd = 0;
|
||||||
|
camWidth = (unsigned int)strtol(argv[i], &pEnd, 10);
|
||||||
|
if (*pEnd != 0 && *(pEnd + 1) != 0)
|
||||||
|
camHeight = strtol(pEnd + 1, &pEnd, 10);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'n':
|
||||||
|
i++;
|
||||||
|
if (i < argc)
|
||||||
|
maxNumb = strtol(argv[i], &pEnd, 10);
|
||||||
|
if (maxNumb > maxMaxNumb) maxNumb = maxMaxNumb;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 's':
|
||||||
|
silent = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '?':
|
||||||
|
case 'h':
|
||||||
|
case '-':
|
||||||
|
printf("Usage: imagerec [-options]\n");
|
||||||
|
printf("options:\n");
|
||||||
|
printf(" -h show help\n");
|
||||||
|
printf(" -c commands ASCII command string\n");
|
||||||
|
printf(" -d port TCP/IP-port to listen on\n");
|
||||||
|
printf(" -p device capture device name\n");
|
||||||
|
printf(" -r whidth*hight image resolution\n");
|
||||||
|
printf(" -n pixels max number of pixels for l command\n");
|
||||||
|
printf(" -f file file path for w command (# for index)\n");
|
||||||
|
printf(" -d return result data only\n");
|
||||||
|
printf("\n");
|
||||||
|
printf("examples: imagerec -d /dev/video0 -r 640*480 -p 5044\n");
|
||||||
|
printf(" imagerec -d /dev/video0 -r 640*480 -c cgnexCngml -s\n");
|
||||||
|
printf(" imagerec -d /dev/video0 -r 640*480 -c cgnexCnw -f result.tif\n");
|
||||||
|
printf(" imagerec -d /dev/video0 -r 640*480 -c cgnwexsonwrCnw -f result#.tif\n");
|
||||||
|
printf("\n");
|
||||||
|
printf("single byte ASCII commands:\n");
|
||||||
|
printf(" c capture image\n");
|
||||||
|
printf(" n normalize image\n");
|
||||||
|
printf(" g apply gausian blur\n");
|
||||||
|
printf(" e edge detection with sobel filter, must be\n");
|
||||||
|
printf(" folowd by 'x', 'o' or a hough transformation\n");
|
||||||
|
printf(" x remove non edge pixel, must be folowd by\n");
|
||||||
|
printf(" 'o' or a hough transformation\n");
|
||||||
|
printf(" o convert directional slope to absolute slope\n");
|
||||||
|
printf(" C circle hough transformation\n");
|
||||||
|
printf(" L line hough transformation\n");
|
||||||
|
printf(" H line hough transformation (horizontal only)\n");
|
||||||
|
printf(" V line hough transformation (vertical only)\n");
|
||||||
|
printf(" M miniscus hough transformation\n");
|
||||||
|
printf(" b binarize\n");
|
||||||
|
printf(" m remove non-local-maxima pixels\n");
|
||||||
|
printf(" l list brightes pixels (from max. 32 non black pixels)\n");
|
||||||
|
printf(" p list brightes pixel clusters (3x3)\n");
|
||||||
|
printf(" q close connection\n");
|
||||||
|
printf(" s store a copy of the current buffer\n");
|
||||||
|
printf(" r recall a copy of the stored buffer\n");
|
||||||
|
printf(" w write buffer to disk (TIF format)\n");
|
||||||
|
printf(" z set index for output file name to zero\n");
|
||||||
|
printf(" d show result data only\n");
|
||||||
|
printf(" i show info and result data (default)\n");
|
||||||
|
printf("\n");
|
||||||
|
printf("example: echo \"cngexCngmlq\" | nc localhost 5044\n");
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
default:
|
||||||
|
printf("Unknown option: -%c\n", *(argv[i] + 1));
|
||||||
|
printf("Type imagerec -h for help\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!silent)
|
||||||
|
{
|
||||||
|
if (port > 0)
|
||||||
|
printf("Start up ImageRecTool, listen on tcp port %i\n", port);
|
||||||
|
else
|
||||||
|
printf("Start up ImageRecTool\n", port);
|
||||||
|
printf("Type imagerec -h for help\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int fd = open((const char*)deviceName, O_RDWR);
|
||||||
|
if (fd == -1)
|
||||||
|
{
|
||||||
|
perror("Opening video device failed");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct v4l2_cropcap crcap = { 0 };
|
||||||
|
|
||||||
|
if (configImageFormat(fd, &crcap, camWidth, camHeight))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
buffSize = (unsigned)setImageSize((int)crcap.bounds.width, (int)crcap.bounds.height);
|
||||||
|
for (int i = 0; i < buffCount; i++)
|
||||||
|
{
|
||||||
|
buffers[i] = (imageBuffer*)malloc(buffSize * sizeof(imageBuffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (initMmap(fd))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (port > 0)
|
||||||
|
{
|
||||||
|
if (!setupCmdTcpServer(port))
|
||||||
|
{
|
||||||
|
perror("Opening tcp port failed");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
useTcpIp = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret = 1;
|
||||||
|
|
||||||
|
while (!exitFlag)
|
||||||
|
{
|
||||||
|
if (useTcpIp)
|
||||||
|
{
|
||||||
|
ret = waitForTcpData(buff, 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buff[0] = *commandStr;
|
||||||
|
commandStr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
cbuff = nbuff;
|
||||||
|
|
||||||
|
switch (buff[0])
|
||||||
|
{
|
||||||
|
case 'c':
|
||||||
|
if (captureImage(fd, buffers[cbuff], buffSize * sizeof(imageBuffer)))
|
||||||
|
return 1;
|
||||||
|
printOut("#image captured\n");
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
nbuff = !cbuff;
|
||||||
|
normalizeImage(buffers[cbuff], buffers[nbuff]); //0.2 ms
|
||||||
|
printOut("#image normalized\n");
|
||||||
|
break;
|
||||||
|
case 'g':
|
||||||
|
gausFilter(buffers[cbuff], buffers[!cbuff]); // 14 ms
|
||||||
|
printOut("#gaus filter applied\n");
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
nbuff = !cbuff;
|
||||||
|
sobelFilter(buffers[cbuff], buffers[nbuff]); //14 ms
|
||||||
|
printOut("#edges detection by sobel filter applied\n");
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
nbuff = !cbuff;
|
||||||
|
nonMaximumSuppression(buffers[cbuff], buffers[nbuff], 128); //9 ms
|
||||||
|
printOut("#non-edges removed\n");
|
||||||
|
break;
|
||||||
|
case 'M':
|
||||||
|
nbuff = !cbuff;
|
||||||
|
clearBuffer(buffers[nbuff]); //1.5 ms
|
||||||
|
houghTransformMiniscus(buffers[cbuff], buffers[nbuff]); //36 ms with sqrt
|
||||||
|
printOut("#miniscus hough transformed\n");
|
||||||
|
break;
|
||||||
|
case 'L':
|
||||||
|
nbuff = !cbuff;
|
||||||
|
clearBuffer(buffers[nbuff]); //1.5 ms
|
||||||
|
houghTransformLines(buffers[cbuff], buffers[nbuff]);
|
||||||
|
printOut("#line hough transformed\n");
|
||||||
|
break;
|
||||||
|
case 'H':
|
||||||
|
nbuff = !cbuff;
|
||||||
|
clearBuffer(buffers[nbuff]); //1.5 ms
|
||||||
|
houghTransformHorizontalLines(buffers[cbuff], buffers[nbuff]);
|
||||||
|
printOut("#horizontal lines hough transformed\n");
|
||||||
|
break;
|
||||||
|
case 'V':
|
||||||
|
nbuff = !cbuff;
|
||||||
|
clearBuffer(buffers[nbuff]); //1.5 ms
|
||||||
|
houghTransformVerticalLines(buffers[cbuff], buffers[nbuff]);
|
||||||
|
printOut("#vertical lines hough transformed\n");
|
||||||
|
break;
|
||||||
|
case 'C':
|
||||||
|
nbuff = !cbuff;
|
||||||
|
clearBuffer(buffers[nbuff]); //1.5 ms
|
||||||
|
houghTransformCircles(buffers[cbuff], buffers[nbuff]);
|
||||||
|
printOut("#circle hough transformed\n");
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
nbuff = !cbuff;
|
||||||
|
findMaxima(buffers[cbuff], buffers[nbuff], 0x10000 / 5, 32); // 0.5 ms
|
||||||
|
printOut("#non-maxima pixels removed\n");
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
binarize(buffers[cbuff], buffers[cbuff], 0x10000 / 2); //0.2 ms
|
||||||
|
printOut("#image normalized\n");
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
nbuff = !cbuff;
|
||||||
|
convertToSlope(buffers[cbuff], buffers[nbuff]); //0.2 ms
|
||||||
|
printOut("#converted to slope\n");
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
itemCount = getPixelList(buffers[cbuff], buffers[cbuff], maxima, maxNumb);
|
||||||
|
printOut("#pixel list: (x y value)\n");
|
||||||
|
for (int i = 0; i < itemCount; i++)
|
||||||
|
{
|
||||||
|
numberToString(maxima[i].x, 0);
|
||||||
|
printOutChar(' ');
|
||||||
|
numberToString(maxima[i].y, 0);
|
||||||
|
printOutChar(' ');
|
||||||
|
numberToString(maxima[i].value[4], 0);
|
||||||
|
printOutChar('\n');
|
||||||
|
}
|
||||||
|
if (useTcpIp) sendTcpData("\n", 1);
|
||||||
|
printOut("#end of list\n");
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
itemCount = getPixelList(buffers[cbuff], buffers[!cbuff], maxima, maxNumb);
|
||||||
|
printOut("#pixel list: (x y value)\n");
|
||||||
|
for (int i = 0; i < itemCount; i++)
|
||||||
|
{
|
||||||
|
numberToString(maxima[i].x, 0);
|
||||||
|
printOutChar(' ');
|
||||||
|
numberToString(maxima[i].y, 0);
|
||||||
|
for (j = 0; j < 9; j++)
|
||||||
|
{
|
||||||
|
printOutChar(' ');
|
||||||
|
numberToString(maxima[i].value[j], 0);
|
||||||
|
}
|
||||||
|
printOutChar('\n');
|
||||||
|
}
|
||||||
|
if (useTcpIp) sendTcpData("\n", 1);
|
||||||
|
printOut("#end of list\n");
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
if (fnIncrPos > -1) filePath[fnIncrPos] = fnIncr + 48;
|
||||||
|
if (write16BitTiff(buffers[cbuff], crcap.bounds.width, crcap.bounds.height, filePath))
|
||||||
|
printOut("#image written\n");
|
||||||
|
else
|
||||||
|
printOut("#error open file\n");
|
||||||
|
|
||||||
|
fnIncr++;
|
||||||
|
if (fnIncr > 9) fnIncr = 0;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
//swap current buffer with storage buffer (buffer 2)
|
||||||
|
tmpib = buffers[2];
|
||||||
|
buffers[2] = buffers[nbuff];
|
||||||
|
buffers[nbuff] = tmpib;
|
||||||
|
|
||||||
|
nbuff = 2;
|
||||||
|
printOut("#image data stored\n");
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
nbuff = 2;
|
||||||
|
printOut("#image data recalled\n");
|
||||||
|
break;
|
||||||
|
case 'q':
|
||||||
|
nbuff = 2;
|
||||||
|
printOut("#close socket\n");
|
||||||
|
closeTcpConnection();
|
||||||
|
break;
|
||||||
|
case 'Q':
|
||||||
|
printOut("#quit application\n");
|
||||||
|
exitFlag = 1;
|
||||||
|
break;
|
||||||
|
case 'z':
|
||||||
|
fnIncr = 0;
|
||||||
|
printOut("#reset index to zero\n");
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
tcpsilent = 0;
|
||||||
|
printOut("#show info and results over tcp/ip\n");
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
tcpsilent = 1;
|
||||||
|
printOut("#show only results over tcp/ip\n");
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
//end of -c command parameter
|
||||||
|
exitFlag = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (buff[0] > 32)
|
||||||
|
printOut("#unknown command\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (useTcpIp)
|
||||||
|
{
|
||||||
|
closeTcpConnection();
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!silent) printf("quit program\n");
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
src/main.o: src/main.c src/imageRec.h src/cmdTcpipClient.h
|
||||||
|
|
||||||
|
src/imageRec.h:
|
||||||
|
|
||||||
|
src/cmdTcpipClient.h:
|
Binary file not shown.
|
@ -0,0 +1,14 @@
|
||||||
|
# Set up paths and environment for cross compiling for openwrt
|
||||||
|
export STAGING_DIR=/home/build/openwrt/staging_dir
|
||||||
|
export TOOLCHAIN_DIR=$STAGING_DIR/toolchain-mipsel_24kc_gcc-7.3.0_musl
|
||||||
|
export LDCFLAGS=$TOOLCHAIN_DIR/usr/lib
|
||||||
|
export LD_LIBRARY_PATH=$TOOLCHAIN_DIR/usr/lib
|
||||||
|
export PATH=$TOOLCHAIN_DIR/bin:$PATH
|
||||||
|
|
||||||
|
mipsel-openwrt-linux-gcc
|
||||||
|
|
||||||
|
/home/build/openwrt/staging_dir/toolchain-mipsel_24kc_gcc-7.3.0_musl/bin
|
||||||
|
|
||||||
|
/home/build/openwrt/staging_dir/toolchain-mipsel_24kc_gcc-7.3.0_musl
|
||||||
|
|
||||||
|
mipsel-openwrt-linux-gcc
|
Loading…
Reference in New Issue