Hôm nay: Mon Nov 23, 2020 11:30 pm

Tìm thấy 7 mục

Hướng dẫn gửi (post) bài viết

Dùng bbCode mcode để được như sau

[mcode]
#include "stdafx.h"
int main()
{
   printf ("Hello world!");
}
 [/mcode]
by Admin
on Wed Nov 20, 2019 5:29 pm
 
Search in: THÔNG BÁO CHUNG
Chủ đề: Hướng dẫn gửi (post) bài viết
Trả lời: 6
Xem: 702

Lập trình tiến hóa_Ví dụ đơn giản

Đã chỉnh sửa để chạy trên Visual Studio 2012

#include "stdafx.h"
#include <Windows.h>
#include <iostream>
#include <vector>
#include <time.h>
#include <algorithm>



//lets create a population
struct Member {
   std::string DNA;
   int Fitness;
};

struct Population {
   std::vector<Member> Members; // this will create a population with 50k members, lets choose a lower number first to see the progress, works fine...
};


int main() {
   //for this example we are going to use a string as a kind of "goal" to achieve
   std::string DNA = "I am a DNA string that needs to be found, shall happen soon!";
   bool SequenceFound = false;
   int MutationRate = 25; // We are going to use this for mutation of genes 1000 = 100% 1 = .01% mutation rate
   srand(time(NULL));

   //create a population and initialize it with random DNA, also set the fitness to 0
   Population Pop;
   Pop.Members = std::vector<Member>(50000);
   
   for (int i = 0; i < Pop.Members.size(); i++) {
       Pop.Members.at(i).DNA.resize(DNA.size());
       for (int j = 0; j < DNA.size(); j++) { Pop.Members.at(i).DNA.at(j) = (unsigned char)rand() % 96 + 32; }
       Pop.Members.at(i).Fitness = 0;
   }

   //we will use a variable to keep track of how many generations there have been
   int Generation = 0;

   //our actuall work will be inside this loop, it will stop when the DNA sequence has fully evolved to the target
   while (!SequenceFound) {
       Generation++;

       //clear out the fitness here and then reevaluate for each member, also check if fitness has reached maximum
       for (int i = 0; i < Pop.Members.size(); i++) {
           Pop.Members.at(i).Fitness = 0;
           for (int j = 0; j < Pop.Members.at(i).DNA.size(); j++) { if (Pop.Members.at(i).DNA.at(j) == DNA.at(j)) { Pop.Members.at(i).Fitness += 10; } }
           if (Pop.Members.at(i).Fitness == DNA.size() * 10) SequenceFound = true;
       }

       //now lets sort the population by fitness, from highest to lowest
       std::sort(Pop.Members.begin(), Pop.Members.end(), [](Member const &a, Member &b) {return a.Fitness > b.Fitness; });

       //select x amount of highest fitness members to pair from, lets use 2 parents in this case
       std::vector<Member> Parents;
       Parents.push_back(Pop.Members.at(0));
       Parents.push_back(Pop.Members.at(1));

       //lets do some gene permutation and mating
       for (int i = 0; i < Pop.Members.size(); i++) {

           for (int j = 0; j < Pop.Members.at(i).DNA.size(); j++) {

               //lets use an equal chance to take each parents gene (on a per gene basis)
               int TempSelection = rand() % Parents.size();
               Pop.Members.at(i).DNA.at(j) = Parents.at(TempSelection).DNA.at(j);

               //dont forget to apply random mutation based on our value from above
               if (rand() % 1000 < MutationRate) { Pop.Members.at(i).DNA.at(j) = (unsigned char)rand() % 96 + 32; }
           }
       }
       
       //lets print some stuff
       std::cout << "Generation : " << Generation << " Highest Fitness : " << Parents.at(0).Fitness << " With Sequence : " << Parents.at(0).DNA.c_str() << std::endl;
   }

   std::cout << "Generation " << Generation << " Evolved to the full sequence" << std::endl;
   Sleep(2000);
   
   return 0;
}



Topics tagged under include on OPENLAB-IMAGE PROCESSING Gp110
by jackauk
on Sat Oct 27, 2018 10:17 pm
 
Search in: HỌC TẬP THEO CHUYÊN ĐỀ
Chủ đề: Lập trình tiến hóa_Ví dụ đơn giản
Trả lời: 1
Xem: 378

Lập trình tiến hóa_Ví dụ đơn giản

Code mẫu Visual Studio 2015 C++14 đã viết:
     #include "stdafx.h"  
#include <Windows.h>
         #include <iostream>
         #include <vector>
         #include <time.h>
         #include <algorithm>



         //lets create a population
         struct Member {
         std::string DNA;
         int Fitness;
         };

         struct Population {
         std::vector<Member> Members = std::vector<Member>(50000); // this will create a population with 50k members, lets choose a lower number first to see the progress, works fine...
         };


         int main() {
         //for this example we are going to use a string as a kind of "goal" to achieve
         std::string DNA = "I am a DNA string that needs to be found, shall happen soon!";
         bool SequenceFound = false;
         int MutationRate = 25; // We are going to use this for mutation of genes 1000 = 100% 1 = .01% mutation rate
         srand(time(NULL));

         //create a population and initialize it with random DNA, also set the fitness to 0
         Population Pop;

         for (int i = 0; i < Pop.Members.size(); i++) {
         Pop.Members.at(i).DNA.resize(DNA.size());
         for (int j = 0; j < DNA.size(); j++) { Pop.Members.at(i).DNA.at(j) = (unsigned char)rand() % 96 + 32; }
         Pop.Members.at(i).Fitness = 0;
         }

         //we will use a variable to keep track of how many generations there have been
         int Generation = 0;

         //our actuall work will be inside this loop, it will stop when the DNA sequence has fully evolved to the target
         while (!SequenceFound) {
         Generation++;

         //clear out the fitness here and then reevaluate for each member, also check if fitness has reached maximum
         for (int i = 0; i < Pop.Members.size(); i++) {
         Pop.Members.at(i).Fitness = 0;
         for (int j = 0; j < Pop.Members.at(i).DNA.size(); j++) { if (Pop.Members.at(i).DNA.at(j) == DNA.at(j)) { Pop.Members.at(i).Fitness += 10; } }
         if (Pop.Members.at(i).Fitness == DNA.size() * 10) SequenceFound = true;
         }

         //now lets sort the population by fitness, from highest to lowest
         std::sort(Pop.Members.begin(), Pop.Members.end(), [](Member const &a, Member &b) {return a.Fitness > b.Fitness; });

         //select x amount of highest fitness members to pair from, lets use 2 parents in this case
         std::vector<Member> Parents{ Pop.Members.at(0), Pop.Members.at(1) };

         //lets do some gene permutation and mating
         for (int i = 0; i < Pop.Members.size(); i++) {

         for (int j = 0; j < Pop.Members.at(i).DNA.size(); j++) {

         //lets use an equal chance to take each parents gene (on a per gene basis)
         int TempSelection = rand() % Parents.size();
         Pop.Members.at(i).DNA.at(j) = Parents.at(TempSelection).DNA.at(j);

         //dont forget to apply random mutation based on our value from above
         if (rand() % 1000 < MutationRate) { Pop.Members.at(i).DNA.at(j) = (unsigned char)rand() % 96 + 32; }
         }
         }

         //lets print some stuff
         std::cout << "Generation : " << Generation << " Highest Fitness : " << Parents.at(0).Fitness << " With Sequence : " << Parents.at(0).DNA.c_str() << std::endl;
         }

         std::cout << "Generation " << Generation << " Evolved to the full sequence" << std::endl;
         Sleep(2000);
         return 0;
         }
by jackauk
on Tue Oct 23, 2018 10:37 pm
 
Search in: HỌC TẬP THEO CHUYÊN ĐỀ
Chủ đề: Lập trình tiến hóa_Ví dụ đơn giản
Trả lời: 1
Xem: 378

Thư viện xử lý ảnh OpenCV 3.3.1

OpenCV (Open Source Computer Vision Library: http://opencv.org) là một open-source BSD-licensed library (Thư viện mã nguồn mở không giới hạn bản quyền)  bao gồm hàng trăm thuật toán thị giác máy tính.Tài liệu này mô tả những hàm API OpenCV 2.x , về cơ bản là các hàm  API C++ , trái ngược với các hàm OpenCV 1.x  dựa trên C. mà được mô tả trong các tài liệu opencv1x.pdf.

OpenCV has a modular structure, which means that the package includes several shared or static libraries. The following modules are available:

Core functionality - a compact module defining basic data structures, including the dense multi-dimensional array Mat and basic functions used by all other modules.
Image processing - an image processing module that includes linear and non-linear image filtering, geometrical image transformations (resize, affine and perspective warping, generic table-based remapping), color space conversion, histograms, and so on.
video - a video analysis module that includes motion estimation, background subtraction, and object tracking algorithms.
calib3d - basic multiple-view geometry algorithms, single and stereo camera calibration, object pose estimation, stereo correspondence algorithms, and elements of 3D reconstruction.
features2d - salient feature detectors, descriptors, and descriptor matchers.
objdetect - detection of objects and instances of the predefined classes (for example, faces, eyes, mugs, people, cars, and so on).
highgui - Một giao diện dễ dùng để thực hiện việc giao tiếp UI đơn giản.
Video I/O - Một giao diện dễ dùng để thu và mã hóa video.
gpu - Các thuật toán tăng tốc GPU từ các modun OpenCV khác.
... và nhiều modun hữu ích như FLANN and Google test wrappers, Python bindings, và nhiều thứ khách.


Các khái niệm API

Namespace cv

Tất cả các lớp và hàm của OpenCV đều đặt trong namespace cv. Do đó, để truy xuất vào các hàm, có thể sử dụng  cv:: specifier hay  using namespace cv; cụ thể như:

Code:
#include "opencv2/core.hpp"
...
cv::Mat H = cv::findHomography(points1, points2, CV_RANSAC, 5);
...

Hay :

Code:
#include "opencv2/core.hpp"
using namespace cv;
...
Mat H = findHomography(points1, points2, CV_RANSAC, 5 );
...

Một số hàm OpenCV trong hiện tại hoặc tương có thể có tên bị xung đột với thư viện STL hay các thư viện khác.Trong trường hợp này, Sử dụng các namespace rõ ràng để tránh xung đột tên:
Ví du ở dưới là 2 hàm log của 2 thư viện
Code:

Mat a(100, 100, CV_32F);
randu(a, Scalar::all(1), Scalar::all(std::rand()));
cv::log(a, a);
a /= std::log(2.);


Quản lý bộ nhớ tự động

OpenCV xử lý tất cả bộ nhớ một cách tự động.
Đầu tiên, std::vector, Mat và các cấu trúc data khác được sử dụng bởi các hàm hay phương thức đều có có các phép hủy nghĩa là được phân bổ dưới bộ đệm khi cần. Điều này có nghĩa là các phép destructor không phải luôn luôn được cấp phát bộ đệm như trong trường hợp Mat. Chúng được tính đến khả năng chia sẻ dữ liệu. Một destructor làm giảm số tham chiếu liên kết tới bộ đệm dữ liệu của ma trận. Bộ đệm được cấp phát khi và chỉ khi số tham chiếu tới nó là không, nghĩa là khi không có một cấu trúc nào tham chiếu tới vùng đệm tương đương. TƯơng đương vậy khi một thực thể Mat được sao chép, không có một chút data nào được sao chép. Thay vào đó, bộ đếm tham chiếu sẽ được tăng lên để ghi nhớ rằng có thêm một đối tượng khác sở hữu cùng dữ liệu đó. Có phương thức Mat::clone cũng tạo một bản sao chép đầy đủ của một dữ liệu ma trận. Xem thêm ví dụ dưới:
First of all, std::vector, Mat, and other data structures used by the functions and methods have destructors that deallocate the underlying memory buffers when needed. This means that the destructors do not always deallocate the buffers as in case of Mat. They take into account possible data sharing. A destructor decrements the reference counter associated with the matrix data buffer. The buffer is deallocated if and only if the reference counter reaches zero, that is, when no other structures refer to the same buffer. Similarly, when a Mat instance is copied, no actual data is really copied. Instead, the reference counter is incremented to memorize that there is another owner of the same data. There is also the Mat::clone method that creates a full copy of the matrix data. See the example below:

// create a big 8Mb matrix
Mat A(1000, 1000, CV_64F);
// create another header for the same matrix;
// this is an instant operation, regardless of the matrix size.
Mat B = A;
// create another header for the 3-rd row of A; no data is copied either
Mat C = B.row(3);
// now create a separate copy of the matrix
Mat D = B.clone();
// copy the 5-th row of B to C, that is, copy the 5-th row of A
// to the 3-rd row of A.
B.row(5).copyTo(C);
// now let A and D share the data; after that the modified version
// of A is still referenced by B and C.
A = D;
// now make B an empty matrix (which references no memory buffers),
// but the modified version of A will still be referenced by C,
// despite that C is just a single row of the original A
B.release();
// finally, make a full copy of C. As a result, the big modified
// matrix will be deallocated, since it is not referenced by anyone
C = C.clone();
You see that the use of Mat and other basic structures is simple. But what about high-level classes or even user data types created without taking automatic memory management into account? For them, OpenCV offers the Ptr template class that is similar to std::shared_ptr from C++11. So, instead of using plain pointers:

T* ptr = new T(...);
you can use:

Ptr<T> ptr(new T(...));
or:

Ptr<T> ptr = makePtr<T>(...);
Ptr<T> encapsulates a pointer to a T instance and a reference counter associated with the pointer. See the Ptr description for details.

Automatic Allocation of the Output Data

OpenCV deallocates the memory automatically, as well as automatically allocates the memory for output function parameters most of the time. So, if a function has one or more input arrays (cv::Mat instances) and some output arrays, the output arrays are automatically allocated or reallocated. The size and type of the output arrays are determined from the size and type of input arrays. If needed, the functions take extra parameters that help to figure out the output array properties.

Example:

#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
using namespace cv;
int main(int, char**)
{
   VideoCapture cap(0);
   if(!cap.isOpened()) return -1;
   Mat frame, edges;
   namedWindow("edges",1);
   for(;Wink
   {
       cap >> frame;
       cvtColor(frame, edges, COLOR_BGR2GRAY);
       GaussianBlur(edges, edges, Size(7,7), 1.5, 1.5);
       Canny(edges, edges, 0, 30, 3);
       imshow("edges", edges);
       if(waitKey(30) >= 0) break;
   }
   return 0;
}
The array frame is automatically allocated by the >> operator since the video frame resolution and the bit-depth is known to the video capturing module. The array edges is automatically allocated by the cvtColor function. It has the same size and the bit-depth as the input array. The number of channels is 1 because the color conversion code COLOR_BGR2GRAY is passed, which means a color to grayscale conversion. Note that frame and edges are allocated only once during the first execution of the loop body since all the next video frames have the same resolution. If you somehow change the video resolution, the arrays are automatically reallocated.

The key component of this technology is the Mat::create method. It takes the desired array size and type. If the array already has the specified size and type, the method does nothing. Otherwise, it releases the previously allocated data, if any (this part involves decrementing the reference counter and comparing it with zero), and then allocates a new buffer of the required size. Most functions call the Mat::create method for each output array, and so the automatic output data allocation is implemented.

Some notable exceptions from this scheme are cv::mixChannels, cv::RNG::fill, and a few other functions and methods. They are not able to allocate the output array, so you have to do this in advance.

Saturation Arithmetics

As a computer vision library, OpenCV deals a lot with image pixels that are often encoded in a compact, 8- or 16-bit per channel, form and thus have a limited value range. Furthermore, certain operations on images, like color space conversions, brightness/contrast adjustments, sharpening, complex interpolation (bi-cubic, Lanczos) can produce values out of the available range. If you just store the lowest 8 (16) bits of the result, this results in visual artifacts and may affect a further image analysis. To solve this problem, the so-called saturation arithmetics is used. For example, to store r, the result of an operation, to an 8-bit image, you find the nearest value within the 0..255 range:

I(x,y)=min(max(round(r),0),255)
Similar rules are applied to 8-bit signed, 16-bit signed and unsigned types. This semantics is used everywhere in the library. In C++ code, it is done using the saturate_cast<> functions that resemble standard C++ cast operations. See below the implementation of the formula provided above:

I.at<uchar>(y, x) = saturate_cast<uchar>(r);
where cv::uchar is an OpenCV 8-bit unsigned integer type. In the optimized SIMD code, such SSE2 instructions as paddusb, packuswb, and so on are used. They help achieve exactly the same behavior as in C++ code.

Note
Saturation is not applied when the result is 32-bit integer.
Fixed Pixel Types. Limited Use of Templates

Templates is a great feature of C++ that enables implementation of very powerful, efficient and yet safe data structures and algorithms. However, the extensive use of templates may dramatically increase compilation time and code size. Besides, it is difficult to separate an interface and implementation when templates are used exclusively. This could be fine for basic algorithms but not good for computer vision libraries where a single algorithm may span thousands lines of code. Because of this and also to simplify development of bindings for other languages, like Python, Java, Matlab that do not have templates at all or have limited template capabilities, the current OpenCV implementation is based on polymorphism and runtime dispatching over templates. In those places where runtime dispatching would be too slow (like pixel access operators), impossible (generic Ptr<> implementation), or just very inconvenient (saturate_cast<>()) the current implementation introduces small template classes, methods, and functions. Anywhere else in the current OpenCV version the use of templates is limited.

Consequently, there is a limited fixed set of primitive data types the library can operate on. That is, array elements should have one of the following types:

8-bit unsigned integer (uchar)
8-bit signed integer (schar)
16-bit unsigned integer (ushort)
16-bit signed integer (short)
32-bit signed integer (int)
32-bit floating-point number (float)
64-bit floating-point number (double)
a tuple of several elements where all elements have the same type (one of the above). An array whose elements are such tuples, are called multi-channel arrays, as opposite to the single-channel arrays, whose elements are scalar values. The maximum possible number of channels is defined by the CV_CN_MAX constant, which is currently set to 512.
For these basic types, the following enumeration is applied:

enum { CV_8U=0, CV_8S=1, CV_16U=2, CV_16S=3, CV_32S=4, CV_32F=5, CV_64F=6 };
Multi-channel (n-channel) types can be specified using the following options:

CV_8UC1 ... CV_64FC4 constants (for a number of channels from 1 to 4)
CV_8UC(n) ... CV_64FC(n) or CV_MAKETYPE(CV_8U, n) ... CV_MAKETYPE(CV_64F, n) macros when the number of channels is more than 4 or unknown at the compilation time.
Note
CV_32FC1 == CV_32F, CV_32FC2 == CV_32FC(2) == CV_MAKETYPE(CV_32F, 2), and CV_MAKETYPE(depth, n) == ((depth&7) + ((n-1)<<3)`. This means that the constant type is formed from the depth, taking the lowest 3 bits, and the number of channels minus 1, taking the next log2(CV_CN_MAX)` bits.
Examples:

Mat mtx(3, 3, CV_32F); // make a 3x3 floating-point matrix
Mat cmtx(10, 1, CV_64FC2); // make a 10x1 2-channel floating-point
                          // matrix (10-element complex vector)
Mat img(Size(1920, 1080), CV_8UC3); // make a 3-channel (color) image
                                   // of 1920 columns and 1080 rows.
Mat grayscale(image.size(), CV_MAKETYPE(image.depth(), 1)); // make a 1-channel image of
                                                           // the same size and same
                                                           // channel type as img
Arrays with more complex elements cannot be constructed or processed using OpenCV. Furthermore, each function or method can handle only a subset of all possible array types. Usually, the more complex the algorithm is, the smaller the supported subset of formats is. See below typical examples of such limitations:

The face detection algorithm only works with 8-bit grayscale or color images.
Linear algebra functions and most of the machine learning algorithms work with floating-point arrays only.
Basic functions, such as cv::add, support all types.
Color space conversion functions support 8-bit unsigned, 16-bit unsigned, and 32-bit floating-point types.
The subset of supported types for each function has been defined from practical needs and could be extended in future based on user requests.

InputArray and OutputArray

Many OpenCV functions process dense 2-dimensional or multi-dimensional numerical arrays. Usually, such functions take cppMat as parameters, but in some cases it's more convenient to use std::vector<> (for a point set, for example) or Matx<> (for 3x3 homography matrix and such). To avoid many duplicates in the API, special "proxy" classes have been introduced. The base "proxy" class is InputArray. It is used for passing read-only arrays on a function input. The derived from InputArray class OutputArray is used to specify an output array for a function. Normally, you should not care of those intermediate types (and you should not declare variables of those types explicitly) - it will all just work automatically. You can assume that instead of InputArray/OutputArray you can always use Mat, std::vector<>, Matx<>, Vec<> or Scalar. When a function has an optional input or output array, and you do not have or do not want one, pass cv::noArray().

Error Handling

OpenCV uses exceptions to signal critical errors. When the input data has a correct format and belongs to the specified value range, but the algorithm cannot succeed for some reason (for example, the optimization algorithm did not converge), it returns a special error code (typically, just a boolean variable).

The exceptions can be instances of the cv::Exception class or its derivatives. In its turn, cv::Exception is a derivative of std::exception. So it can be gracefully handled in the code using other standard C++ library components.

The exception is typically thrown either using the CV_Error(errcode, description) macro, or its printf-like CV_Error_(errcode, printf-spec, (printf-args)) variant, or using the CV_Assert(condition) macro that checks the condition and throws an exception when it is not satisfied. For performance-critical code, there is CV_DbgAssert(condition) that is only retained in the Debug configuration. Due to the automatic memory management, all the intermediate buffers are automatically deallocated in case of a sudden error. You only need to add a try statement to catch exceptions, if needed: :

try
{
   ... // call OpenCV
}
catch( cv::Exception& e )
{
   const char* err_msg = e.what();
   std::cout << "exception caught: " << err_msg << std::endl;
}
Multi-threading and Re-enterability

The current OpenCV implementation is fully re-enterable. That is, the same function, the same constant method of a class instance, or the same non-constant method of different class instances can be called from different threads. Also, the same cv::Mat can be used in different threads because the reference-counting operations use the architecture-specific atomic instructions.
by jackauk
on Fri Nov 03, 2017 12:09 am
 
Search in: CÁC THƯ VIỆN LẬP TRÌNH XỬ LÝ ẢNH
Chủ đề: Thư viện xử lý ảnh OpenCV 3.3.1
Trả lời: 0
Xem: 1104

Các bộ lọc_phép biến đổi ảnh trong xử lý ảnh

Bộ lọc hay phép biến đổi Fourier nhanh (Fast Fourier Transform -FFT)
 Một biến đổi Fourier nhanh (FFT) là một thuật toán hiệu quả để tính biến đổi Fourier rời rạc (DFT) và biến đổi ngược. Có nhiều thuật toán FFT khác nhau sử dụng kiến thức từ nhiều mảng khác nhau của toán học, từ số phức tới lý thuyết nhóm và lý thuyết số.
 Phép biến đổi DFT phân tích một dãy các số thành các thành phần ở các tần số khác nhau. Nó được sử dụng trong nhiều lĩnh vực khác nhau (xem các tính chất và ứng dụng ở biến đổi Fourier rời rạc) nhưng tính toán trực tiếp từ định nghĩa thường quá chậm trong thực tế. FFT là một cách để đạt được cùng kết quả đó nhưng nhanh hơn nhiều: tính DFT của N điểm trực tiếp theo định nghĩa đòi hỏi O(N2) phép tính, trong khi FFT tính ra cùng kết quả đó trong O(N log N) phép tính.
Giả sử x0, x1,..., xn là các số phức. DFT được định nghĩa bởi công thức sau:

Topics tagged under include on OPENLAB-IMAGE PROCESSING Fomular

Tính trực tiếp từ định nghĩa trên đòi hỏi O(N2) phép tính: có N số Xk cần tính, để tính mỗi số cần tính một tổng N số hạng. Một FFT là một phương pháp để tính cùng kết quả đó trong O(N log N) phép tính.
Ứng dụng của phép biến đổi này trong xứ lý ảnh là phân tích bức ảnh thay vì dưới dạng không gian 2 chiều của các điểm ảnh có giá trị cường độ sáng thành một miền một chiều theo tần số gọi là phân tích phổ.
Để biết rõ hơn các bạn nên tham khảo về nó trên internet bởi vì riêng kiến thức về nó thôi đã trở thành một ngành khoa học rồi. Trong khuôn khổ chủ đề này mình chỉ muốn giới thiệu ứng dụng của nó để các bạn có thể lựa chọn phương pháp lọc cùa mình cho phù hợp với yêu cầu.


Biến đổi Fourier sẽ phân tích một bức ảnh thành hai thành phần cos và sin. Nói cách khác, nó biến đổi ảnh từ miền không gian sang miền tần số. Ý tưởng là có một hàm nào đó có thể xấp xỉ một cách chính xác với tổng vô hạn của hàm sin và cos. Biến đổi Fourier là cách để làm điều đó. Dạng toán học của biến đổi Fourier ảnh hai chiều là :
Topics tagged under include on OPENLAB-IMAGE PROCESSING Fomular2
f ở đây là giá trị ảnh trong miền không gian và F là giá trị ảnh trong miền tần số. Kết quả của phép biến đổi là tập số phức. Điều này có thể biểu diễn thông qua một ảnh thực và một ảnh phức hay thông qua độ lớn và một ảnh pha. Tuy nhiên qua thuật toán biến đổi ảnh thì chỉ có ảnh biên độ mới có giá trị bởi nó chứa tất cả thông tin về các cấu trúc hình học của ảnh. Tuy vậy, nếu bạn có dự định làm điều gì đó với ảnh biên độ ( cường độ độ lớn) và biến đổi ngược lại về miền không gian thì bạn cần cả hai thành phần ảnh  biên độ và pha (magnitude và phase).
Trong ví dụ sau đây chúng tôi sẽ chỉ cách tính toán và hiển thị ảnh cường độ của phép biến đổi Fourier. Trong trường hợp ảnh số là rời rạc. Có nghĩa là chúng được hiểu là giá trị từ miền giá trị nhận được. Ví dụ là một ảnh xám thường có giá trị điểm ảnh nằm trong khoảng từ 0 đến 255. Do đó phép biến đổi Fourier cần những giá trị kết quả rời rạc. Bạn sẽ muốn sử dụng nó bất cứ khi nào bạn cần xác định cấu trúc của bức ảnh từ tất cả các cấu trúc hình học nào trong tầm mắt. Sau đây là các bước cần thiết cho một ảnh xám đầu vào.

  1. Mở rộng ảnh đến một kích thước tối ưu.
     Phép biến đổi Fourier đạt trạng thái nhanh nhất khi kích thước ảnh là bộ số của 2,3 5.
  2. Tạo nơi chứa cho giá trị phức và giá trị thực
    Lưu ý rằng phép biến đổi kết quả sẽ rất là lẻ, cần nhiều con số để biểu diễn nên lưu trữ chúng dưới dạng float ( CV_32F) chứ không phải kiểu int hay char như ảnh gốc ( 0-255)
  3. Tiến hành biến đổi Fourier rời rạc

  4. Biến đổi giá trị phức và giá trị thực sang dạng biên độ độ lớn
    Topics tagged under include on OPENLAB-IMAGE PROCESSING Magnitude
  5. Biểu diễn dưới dạng logarit
    Do kết quả tính toán vượt giá trị có thể biểu diễn điểm ảnh của màn hình cho nên phải hạ tỷ lệ nó theo logarit cơ số 10. Ví dụ log100 =2, log1000=3.....
  6. Cắt tỉa hình và sắp xếp lại
    Do bước đầu tiên ta giãn ra thì phải co lại theo tỷ lệ gốc để có thể hiển thị được kết quả.
  7. CHuẩn hóa
    Vì mục đích dễ mường tượng kết quả phải chuẩn hóa nó về dạng ảnh xám ý nghĩa là giống như trên một bức ảnh ta có tất cả đều là màu đỏ nhưng mà có cái đỏ đậm có cái đỏ nhạt, có cái phơn phớt ta giãn nó ra thành màu xám màu xanh màu đỏ màu vàng.... thì dễ phân biệt được các màu với nhau.


Code sau là viết với OpenCV 2.4.9 ( các bạn sẽ thấy làm việc với ảnh như một mảng số của Matlab)

1 #include "opencv2/core/core.hpp"
2 #include "opencv2/imgproc/imgproc.hpp"
3 #include "opencv2/highgui/highgui.hpp"
4 #include <iostream>
5 int main(int argc, char ** argv)
6 {
7 const char* filename = argc >=2 ? argv[1] : "lena.jpg";
8
9   Mat I = imread(filename, CV_LOAD_IMAGE_GRAYSCALE);
10 if( I.empty())
11 return -1;
12
13 Mat padded; //expand input image to optimal size
14 int m = getOptimalDFTSize( I.rows );
15 int n = getOptimalDFTSize( I.cols ); // on the border add zero values
16 copyMakeBorder(I, padded, 0, m - I.rows, 0, n - I.cols, BORDER_CONSTANT, Scalar::all(0));
17
18 Mat planes[] = {Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F)};
19 Mat complexI;
20 merge(planes, 2, complexI); // Add to the expanded another plane with zeros
21
22 dft(complexI, complexI); // this way the result may fit in the source matrix
23
24 // compute the magnitude and switch to logarithmic scale
25 // => log(1 + sqrt(Re(DFT(I))^2 + Im(DFT(I))^2))
26 split(complexI, planes); // planes[0] = Re(DFT(I), planes[1] = Im(DFT(I))
27 magnitude(planes[0], planes[1], planes[0]);// planes[0] = magnitude
28 Mat magI = planes[0];
29
30 magI += Scalar::all(1); // switch to logarithmic scale
31 log(magI, magI);
32
33 // crop the spectrum, if it has an odd number of rows or columns
34 magI = magI(Rect(0, 0, magI.cols & -2, magI.rows & -2));
35
36 // rearrange the quadrants of Fourier image so that the origin is at the image center
37 int cx = magI.cols/2;
38 int cy = magI.rows/2;
39
40 Mat q0(magI, Rect(0, 0, cx, cy)); // Top-Left - Create a ROI per quadrant
41 Mat q1(magI, Rect(cx, 0, cx, cy)); // Top-Right
42 Mat q2(magI, Rect(0, cy, cx, cy)); // Bottom-Left
43 Mat q3(magI, Rect(cx, cy, cx, cy)); // Bottom-Right
44
45 Mat tmp; // swap quadrants (Top-Left with Bottom-Right)
46 q0.copyTo(tmp);
47 q3.copyTo(q0);
48 tmp.copyTo(q3);
49
50 q1.copyTo(tmp); // swap quadrant (Top-Right with Bottom-Left)
51 q2.copyTo(q1);
52 tmp.copyTo(q2);
53
54 normalize(magI, magI, 0, 1, CV_MINMAX); // Transform the matrix with float values into a
55 // viewable image form (float between values 0 and 1).
56
57 imshow("Input Image" , I ); // Show the result
58 imshow("spectrum magnitude", magI);
59 waitKey();
60
61 return 0;
62 }

Mình nhắc lại là ta không chắc kết quả của quá trình của biến đổi ảnh khi mà ta không thử trước. Công việc xử lý ảnh không phải là công việc ngày một ngày hai mà là quan trọng là kinh nghiệm của người lập trình trải qua nhiều lần thử nghiệm các phép lọc, phép biến đổi khác nhau. Nhiều phép biến đổi lạ lẫm ta phải thử đi thử lại để đạt được kết quả mong muốn. Có phép biến đổi hợp lý có phép biến đổi chả ra kết quả gì. Ở đây phép biến đổi DFT cho ta cấu trúc hình học chủ yếu của ảnh. Hai ảnh dưới đây cho ta mường tượng hiệu quả của phép biến đổi DFT như thế nào.

Ảnh kết quả của chữ in thẳng.
Topics tagged under include on OPENLAB-IMAGE PROCESSING Result_normal
Ảnh kết quả của ảnh có chữ bị nghiêng
Topics tagged under include on OPENLAB-IMAGE PROCESSING Result_rotated
Sau đó, việc còn lại là ta sẽ dùng các phép lọc, phép biến đổi khác để nhận ra được kết quả mong muốn. 

Hiệu quả của phép biến đổi, xem video sau để rõ hơn:
by jackauk
on Thu Sep 17, 2015 12:57 am
 
Search in: TÀI LIỆU VỀ XỬ LÝ ẢNH CƠ BẢN
Chủ đề: Các bộ lọc_phép biến đổi ảnh trong xử lý ảnh
Trả lời: 20
Xem: 10011

Principal Component Analysis_PCA

Trong đại số tuyến tính số học, các thuật toán QR là một thuật toán eigenvalue. Đó là một thủ tục để tính toán các giá trị riêng và vector riêng của ma trận. Việc chuyển đổi QR đã được phát triển vào cuối những năm 1950 bởi John GF Francis (Anh) và Vera N. Kublanovskaya (Liên Xô), làm việc độc lập. Ý tưởng cơ bản là để thực hiện một phân giải QR là viết lại các ma trận như là một kết quả của một ma trận trực giao và một ma trận tam giác trên, nhân các phần tử trong thứ tự ngược lại, và lặp.
Từ khóa: Ma trận trực giao, ma trận đường chéo, ma trận tam giác trên, Hermitian
Giải thuật:

MATLAB code:

function [ R, Q ] = myqr( A )
 %MYQR Summary of this function goes here
 %   Detailed explanation goes here

 R = A;
 [m, n] = size(R);
 V = zeros(m, n);

 assert(m >= n, 'm should be geq to n');

 for k=1:n
   x = R(k:m,k);
   e = zeros(m-k+1, 1);
   e(1) = 1;
   v = sign(x(1))*norm(x, 2)*e + x;
   v = v./norm(v, 2);
   R(k:m,k:n)=R(k:m,k:n) - 2*v*(v'*R(k:m,k:n));

   V(k:m, k) = v;
 end

 if (nargout == 2)
   Q = zeros(m, m);
   for i=1:m
     ei = zeros(m, 1);
     ei(i) = 1;
     for k=n:-1:1
       ei = ei - 2*V(:,k)*(V(:,k)'*ei);
     end
     Q(:,i) = ei;
   end
 end
end


V C++ code:

#include "stdafx.h"
#include "assert.h"
void qr()
{};
array<double,2>^ transpose(array<double,2>^ src)
{  int r = src->GetLength(0);
  int c =  src->Length/r;
  array<double,2>^ rst = gcnew array<double,2>(c,r);
   for( int i = 0 ; i < c; i++)
for ( int j = 0 ; j < r; j++)
{
rst[i,j]= src[j,i];
}


return rst;

}
array<double,2>^  zeros ( int m , int n )
{  
array<double,2> ^ arrs = gcnew array<double,2>(m,n);

return arrs;

}
array<double,2>^  ones ( int m , int n )
{  
array<double,2> ^ arrs = gcnew array<double,2>(m,n);
for (int i = 0 ; i < m; i++)
for (int j = 0 ; j<n; j++)
{
arrs[i,j]=1;


}
return arrs;

}
array<double,2>^  diagonalmatrix ( int m  )
{  
array<double,2> ^ arrs = gcnew array<double,2>(m,m);
for (int i = 0 ; i < m; i++)
for (int j = 0 ; j<m; j++)
{
if (i==j)
arrs[i,j]=1;
else
arrs[i,j]=0;

}


return arrs;

}
double myNorm(array<double,2>^src)
{ double result;
 int c = src->GetLength(0);
 int r = src->Length/c;
 for (int i = 0 ; i < c;i++)
 for ( int j = 0 ; j <r; j ++)
 {
 result+=  System::Math::Pow(src[i,j],2);
 }



 return System::Math::Sqrt(result);
}
array<double,2>^ subarray(array<double,2>^src, int m1,int m2, int n1,int n2)
{

 int m = m2-m1;
 int n = n2-n1;
 assert(m>=0);
 assert(n>=0);
 int c = src->GetLength(0);
 int r = src->Length/c;
 assert(c>=n);
 assert(r>=m);
array<double,2>^rst =gcnew array<double,2>(m+1,n+1);
int om =m1,on=n1;
 for (int i = m1; i<=m2; i++)
 for (int j = n1; j<=n2; j++)
 { rst[i-om,j-on]=src[i,j];
 
 }
 return rst;
}
array< double ,2>^  mutilple(array<double,2>^ src, double n)
{ int r = src->GetLength(0);
 int c = src->Length/r;
array< double ,2>^rst= gcnew array< double ,2>(r,c);

    for (int i =0; i<r; i++)
 for (int j = 0; j<c; j++)
 { rst[i,j]=src[i,j]*n;
  }

return rst;
}
array< double ,2>^  mutilpleSpecial(array<double,2>^ src1, array<double,2>^ src2)
{
    int n1  = src1->GetLength(0);
  int m1 =  src1->Length/n1;
  int n2  = src2->GetLength(0);
  int m2 =  src2->Length/n2;
  if ((m1!=n2)||(n1!=m2))
  {
  System::Windows::Forms::MessageBox::Show(L"Kiểm tra lại điều kiện nhân ma trận",L"Thông báo");
  assert(-1>0);
 
  }
array<double,2>^ rst = gcnew array<double,2>(n1,n1);
 
    for (int i =0; i<n1; i++)
 for (int j = 0; j<n1; j++)
 {  for ( int k = 0 ; k < m1; k++)
 rst[i,j]+=   src1[i,k]*src2[k,j];
  }

return rst;
}
 array< double ,2>^  mutilple(array<double,2>^ src1, array<double,2>^ src2)
{
  int n1  = src1->GetLength(0);
  int m1 =  src1->Length/n1;
  int n2  = src2->GetLength(0);
  int m2 =  src2->Length/n2;
array<double,2>^ rst = gcnew array<double,2>(n1,n1);

  if ((m1!=n2)||(n1!=m2))
  {        if (n1<m2)
       {rst = gcnew array<double,2>(n1,m1);
        for (int i =0; i<n1; i++)
     for (int j = 0; j<m1; j++)
   {  for ( int k = 0 ; k < m1; k++)
 rst[i,j]+=   src1[i,k]*src2[k,j];
  }
        return rst;
}
    if (m1<n2)
{rst = gcnew array<double,2>(n1,n2);
        for (int i =0; i<n1; i++)
     for (int j = 0; j<n2; j++)
   {  for ( int k = 0 ; k < m1; k++)
 rst[i,j]+=   src1[i,k]*src2[k,j];
  }
        return rst;
}

   if (n1>m2)
{rst = gcnew array<double,2>(n1,m1);
        for (int i =0; i<n1; i++)
     for (int j = 0; j<m1; j++)
   {  for ( int k = 0 ; k < m2; k++)
 rst[i,j]+=   src1[i,k]*src2[k,j];
  }
        return rst;

 

}
 

  System::Windows::Forms::MessageBox::Show(L"Kiểm tra lại điều kiện nhân ma trận",L"Thông báo");
  assert(-1>0);
 
  }
 
    for (int i =0; i<n1; i++)
 for (int j = 0; j<n1; j++)
 {  for ( int k = 0 ; k < m1; k++)
 rst[i,j]+=   src1[i,k]*src2[k,j];
  }

return rst;
}
 array<double,2>^ plus(array<double,2>^ src1, array<double,2>^ src2)
{
  int n1  = src1->GetLength(0);
  int m1 =  src1->Length/n1;
  int n2  = src2->GetLength(0);
  int m2 =  src2->Length/n2;
  if ((m1!=m2)||(n1!=n2))
  {
  System::Windows::Forms::MessageBox::Show(L"Kiểm tra lại điều kiện cộng ma trận",L"Thông báo");
  assert(-1>0);
 
  }
array<double,2>^ rst = gcnew array<double,2>(n1,m1);
 
    for (int i =0; i<n1; i++)
 for (int j = 0; j<m1; j++)
 {  for ( int k = 0 ; k < m1; k++)
 rst[i,j]=   src1[i,j]+src2[i,j];
  }

return rst;
}
  array<double,2>^ minus(array<double,2>^ src1, array<double,2>^ src2)
{
  int n1  = src1->GetLength(0);
  int m1 =  src1->Length/n1;
  int n2  = src2->GetLength(0);
  int m2 =  src2->Length/n2;
  if ((m1!=m2)||(n1!=n2))
  {
  System::Windows::Forms::MessageBox::Show(L"Kiểm tra lại điều kiện trừ ma trận",L"Thông báo");
 assert(-1>0);
 
  }
array<double,2>^ rst = gcnew array<double,2>(n1,m1);
 
    for (int i =0; i<n1; i++)
 for (int j = 0; j<m1; j++)
 {  for ( int k = 0 ; k < m1; k++)
 rst[i,j]=   src1[i,j]-src2[i,j];
  }

return rst;
}
  array< double ,2>^  divide(array<double,2>^ src, double n)
{
  int r  = src->GetLength(0);
  int c =  src->Length/r;
    for (int i =0; i<r; i++)
 for (int j = 0; j<c; j++)
 { src[i,j]/=n;
  }

return src;
}
  double  sign( double n)
  { if ( n <0)
  return -1;
  else  
  return 1;
 
  }
  array<double,2>^ copyarray(array<double,2>^src1,int m1, int m2, int n1, int n2 , array<double,2>^src2)
  {
  int r = src2->GetLength(0);
  int c = src2->Length/r;

 
    if (( m2<m1)||(n2<n1)||(m2-m1+1!= r)||(n2-n1+1!=c))
{ System::Windows::Forms::MessageBox::Show(L"Kiểm tra lại điều kiện chép ma trận",L"Thông báo");
  assert(-1>0);
   }
    for ( int i = m1; i<=m2;i++)
for ( int j = n1;j<=n2;j++)
{  src1[i,j]= src2[i-m1,j-n1];
}
 
    return src1;
  }

void myqr(array<double,2>^ A,array<double,2>^ Q,array<double,2>^ R)
{
  int m  = A->GetLength(0);
  int n =  A->Length/m;
  array<double,2> ^ V = zeros(m,n);
   Q = zeros(m,n);
  assert  (m >= n,"Số hàng phải lớn hơn số cột");
  R = subarray(A,0,m-1,0,n-1);
  for ( int k = 0 ; k < n; k++)
  {
  array<double,2> ^x = subarray(R,k,m-1,k,k);
  array<double,2> ^e = zeros(m-k,1);
   e[0,0]=1;
array<double,2> ^v=  plus(mutilple(e,sign(x[0,0])*myNorm(x)),x);
v= divide(v,myNorm(v));
array<double,2>^ temp = gcnew array<double,2>(v->Length,v->Length);
temp = copyarray(temp,0,0,0,v->Length-1, transpose(v));
array<double,2>^ temp1 =mutilple(temp,subarray(R,k,m-1,k,n-1));
array<double,2>^ temp2 =mutilple(mutilple(v,2),temp1);
R =copyarray(R,k,m-1,k,n-1,minus(subarray(R,k,m-1,k,n-1),temp2));
copyarray(V,k,m-1,k,k,v);
 
  }
  for (int i = 0 ; i < m; i++)
  {
  array<double,2> ^ ei = zeros(m,1);
  ei[i,0]=1;
  for ( int k = n-1 ; k >=0; k--)
  {
  array<double,2>^ temp = mutilple(transpose(subarray(V,0,m-1,k,k)),ei);
  array<double,2> ^temp1 =mutilple( subarray(V,0,m-1,k,k),2);

  ei = minus(ei,mutilple(temp1,temp));
 // ei = ei - 2*V(:,k)*(V(:,k)'*ei);
  }
   //Q(:,i) = ei;
  Q= copyarray(Q,0,m-1,i,i,ei);
  }
 /*  x = R(k:m,k);
   e = zeros(m-k+1, 1);
   e(1) = 1;
   v = sign(x(1))*norm(x, 2)*e + x;
   v = v./norm(v, 2);
   R(k:m,k:n)=R(k:m,k:n) - 2*v*(v'*R(k:m,k:n));

   V(k:m, k) = v;
if (nargout == 2)
   Q = zeros(m, m);
   for i=1:m
     ei = zeros(m, 1);
     ei(i) = 1;
     for k=n:-1:1
       ei = ei - 2*V(:,k)*(V(:,k)'*ei);
     end
     Q(:,i) = ei;
   end
*/


}
by jackauk
on Tue Aug 25, 2015 11:50 pm
 
Search in: TÀI LIỆU VỀ NHẬN DẠNG TRONG XỬ LÝ ẢNH
Chủ đề: Principal Component Analysis_PCA
Trả lời: 3
Xem: 1210

Thư viện xử lý ảnh OpenCV3.0

Lịch sử: #OpenCV
Nguồn download:
Môi trường lập trình:
Cách cài đặt vào Visual Studio 2012,2013
Bước 1: Chuẩn bị các đường dẫn cho việc sử dụng OpenCV 3.0
Mở Property Pages của Project đang làm việc (Alt+F7)
+Configuration Properties> VC++Directories cho ứng dụng Form ( Form Application Project)
>> Include Directories: Điền đường dẫn các folder chứa tập tin header (.h hay .hpp) cho OpenCV
của tôi là D:\Storages\OpenCV3.0\opencv\build\include

>> Library Directories: Điền đường dẫn các folder chứa tập tin library .lib cho OpenCV
của tôi là visual studio 2012 nên dùng bản vc11 của bạn là visual 2013 thì là vc12, tôi dùng hệ điều hành 32 bít thì là x86, bạn dùng hệ 64bit thì là x64
D:\Storages\OpenCV3.0\opencv\build\x86\vc11\lib

>> Source Directories: Điền đường dẫn các folder chứa tập tin header cho OpenCV
của tôi là D:\Storages\OpenCV3.0\opencv\build\x86\vc11\bin

Topics tagged under include on OPENLAB-IMAGE PROCESSING Config%20properties
+Configuration Properties> C/C++ cho ứng dụng Console ( Console Application Projectt)
cũng tương tự như Include Directories phía trên
Topics tagged under include on OPENLAB-IMAGE PROCESSING ConfigC

Bước 2: Thiết lập các thư viện chuẩn cho Debug, Release, Mình hướng dẫn cho phần Debug, phần Release các bạn làm tương tự chỉ thay một chữ cái d sau cùng của tên library opencv_world300d.lib thành opencv_world300.lib là xong
Mở tab Linker trong cửa sổ Property pages
Topics tagged under include on OPENLAB-IMAGE PROCESSING Linker

Bước 3: Khai báo các lớp được dùng, các lớp này là các tập tin header thôi còn các file thực thi đã được thêm vào phía trên rồi, chỉ cần khai bao là Visual Studio tự động biên dịch các thành phần còn lại
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/objdetect.hpp"

Bạn dùng thêm những component khác như detect motion chẳng hạn thì tìm đúng các tệp  header của nó để mà nhúng vào trong chương trình.
Thêm nứa: nếu bạn ngại gõ cv:: trước lệnh nào đó ví dụ như cv::copy để sao chép mảng, ma trận, ảnh thì bạn có thể thêm khai báo sau phía trên cùng sau mấy dòng include
using namespace cv;
Lúc này bạn chỉ cần gõ copy thay vì cv::copy. Mình không khuyến khích điều này vì nó sẽ dễ gây ambigous (định nghĩa không rõ ràng) với những lệnh từ các lớp hay không gian miền khác. Ví dụ abs là hàm trị tuyệt đối có ở rất nhiều thư viện dễ gây lỗi chương trình nếu không chỉ rõ là bạn dùng của lớp nào
by jackauk
on Tue Aug 18, 2015 9:49 pm
 
Search in: CÁC THƯ VIỆN LẬP TRÌNH XỬ LÝ ẢNH
Chủ đề: Thư viện xử lý ảnh OpenCV3.0
Trả lời: 7
Xem: 4711

Về Đầu Trang

Chuyển đến