diff --git a/tests/src/image_rec.c b/tests/src/image_rec.c new file mode 100644 index 0000000..aa0c8de --- /dev/null +++ b/tests/src/image_rec.c @@ -0,0 +1,681 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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(" -p port TCP/IP-port to listen on\n"); + printf(" -d 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; +} \ No newline at end of file diff --git a/tests/src/image_rec2.c b/tests/src/image_rec2.c new file mode 100644 index 0000000..9727948 --- /dev/null +++ b/tests/src/image_rec2.c @@ -0,0 +1,515 @@ +#include +#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); +}