├── .gitignore
├── COPYING.GPL3.txt
├── ImageQ.pro
├── README.txt
├── aboutwindow.cpp
├── aboutwindow.h
├── aboutwindow.ui
├── blurwindow.cpp
├── blurwindow.h
├── blurwindow.ui
├── cannywindow.cpp
├── cannywindow.h
├── cannywindow.ui
├── gradientwindow.cpp
├── gradientwindow.h
├── gradientwindow.ui
├── histogram.cpp
├── histogram.h
├── histogramwindow.cpp
├── histogramwindow.h
├── histogramwindow.ui
├── image.cpp
├── image.h
├── image.ui
├── imagelabel.cpp
├── imagelabel.h
├── main.cpp
├── mainwindow.cpp
├── mainwindow.h
├── mainwindow.ui
├── mat2qimage.cpp
├── mat2qimage.h
├── morphologywindow.cpp
├── morphologywindow.h
├── morphologywindow.ui
├── opencv_future
└── imgproc
│ ├── connectedcomponents.hpp
│ └── src
│ └── connectedcomponents.cpp
├── samples
├── N2_2.kesit.JPG
├── Nanofilaments-EMpicture.jpg
├── Pos.tif
├── Sand_from_Gobi_Desert.jpg
└── license.txt
├── setscalewindow.cpp
├── setscalewindow.h
├── setscalewindow.ui
├── textlistwindow.cpp
├── textlistwindow.h
├── textlistwindow.ui
├── thresholdwindow.cpp
├── thresholdwindow.h
└── thresholdwindow.ui
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled source #
2 | ###################
3 | ImageQ
4 | *.o
5 |
6 | # Automatically generated files #
7 | #################################
8 | ImageQ.pro.user
9 | Makefile
10 | moc_*.cpp
11 | ui_*.h
12 |
--------------------------------------------------------------------------------
/COPYING.GPL3.txt:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 |
635 | Copyright (C)
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | Copyright (C)
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 |
--------------------------------------------------------------------------------
/ImageQ.pro:
--------------------------------------------------------------------------------
1 | QT += core gui
2 |
3 | win32 {
4 | LIBS += -lqwt
5 |
6 | LIBS += -lopencv_core242.dll
7 | LIBS += -lopencv_highgui242.dll
8 | LIBS += -lopencv_imgproc242.dll
9 | }
10 |
11 | unix {
12 | CONFIG += qwt
13 |
14 | LIBS += -lopencv_core
15 | LIBS += -lopencv_highgui
16 | LIBS += -lopencv_imgproc
17 | }
18 |
19 | TARGET = ImageQ
20 | TEMPLATE = app
21 |
22 |
23 | SOURCES += main.cpp\
24 | mainwindow.cpp \
25 | mat2qimage.cpp \
26 | histogram.cpp \
27 | aboutwindow.cpp \
28 | histogramwindow.cpp \
29 | blurwindow.cpp \
30 | cannywindow.cpp \
31 | gradientwindow.cpp \
32 | morphologywindow.cpp \
33 | thresholdwindow.cpp \
34 | image.cpp \
35 | imagelabel.cpp \
36 | setscalewindow.cpp \
37 | textlistwindow.cpp \
38 | opencv_future/imgproc/src/connectedcomponents.cpp
39 |
40 | HEADERS += mainwindow.h \
41 | mat2qimage.h \
42 | histogram.h \
43 | aboutwindow.h \
44 | histogramwindow.h \
45 | blurwindow.h \
46 | cannywindow.h \
47 | gradientwindow.h \
48 | morphologywindow.h \
49 | thresholdwindow.h \
50 | image.h \
51 | imagelabel.h \
52 | setscalewindow.h \
53 | textlistwindow.h \
54 | opencv_future/imgproc/connectedcomponents.hpp
55 |
56 | FORMS += mainwindow.ui \
57 | aboutwindow.ui \
58 | histogramwindow.ui \
59 | blurwindow.ui \
60 | cannywindow.ui \
61 | gradientwindow.ui \
62 | morphologywindow.ui \
63 | thresholdwindow.ui \
64 | image.ui \
65 | setscalewindow.ui \
66 | textlistwindow.ui
67 |
68 | OTHER_FILES += \
69 | README.txt \
70 | COPYING.GPL3.txt
71 |
--------------------------------------------------------------------------------
/README.txt:
--------------------------------------------------------------------------------
1 | ABOUT
2 | =====
3 |
4 | ImageQ is a Qt based image processing application.
5 |
6 | ImageQ uses OpenCV library for the image processing backend and uses Qt and Qwt
7 | libraries for the GUI frontend.
8 |
9 | ImageQ currently provides the following operations:
10 |
11 | + Filtering
12 | + Histogram processing
13 | + Morphology operators
14 | + Edge detection
15 |
16 | With ImageQ, you can see the effect of varying the parameters of these
17 | operations on the go.
18 |
19 | DEPENDENCIES
20 | ============
21 |
22 | + OpenCV (http://opencv.org/) - Developed using version 2.3
23 | + Qt library (http://qt-project.org/) - Developed using version 4.8
24 | + Qwt library (http://sourceforge.net/projects/qwt/) - Developed using version 6
25 |
26 | BUILDING
27 | ========
28 |
29 | $ qmake
30 | $ make
31 |
32 | DEVELOPMENT
33 | ===========
34 |
35 | ImageQ was developed using Qt Creator, which is the recommended IDE for further
36 | development.
37 |
38 | LICENSE
39 | =======
40 |
41 | Most of ImageQ source code is released under the terms of the GNU General Public
42 | License (GPL) version 3.
43 |
44 | See COPYING.GPL3.txt for more details.
45 |
46 | There are two exceptions:
47 |
48 | 1) The files inside the opencv_future folder. Those files are under the Intel
49 | License Agreement For Open Source Computer Vision Library.
50 |
51 | See inside those files for more details.
52 |
53 | 2) The images under the 'samples' folder, those files are licensed under
54 | Creative Commons or belong to the public domain.
55 |
56 | See samples/license.txt for more details.
57 |
--------------------------------------------------------------------------------
/aboutwindow.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Jorge Aparicio
3 | *
4 | * This file is part of ImageQ.
5 | *
6 | * ImageQ is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 |
11 | * ImageQ is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 |
16 | * You should have received a copy of the GNU General Public License
17 | * along with ImageQ. If not, see .
18 | */
19 |
20 | #include "aboutwindow.h"
21 | #include "ui_aboutwindow.h"
22 |
23 | AboutWindow::AboutWindow(QWidget *parent) :
24 | QMainWindow(parent),
25 | ui(new Ui::AboutWindow)
26 | {
27 | ui->setupUi(this);
28 |
29 | this->setAttribute(Qt::WA_DeleteOnClose);
30 | this->setFixedSize(this->size());
31 |
32 | this->show();
33 | }
34 |
35 | AboutWindow::~AboutWindow()
36 | {
37 | delete ui;
38 | }
39 |
--------------------------------------------------------------------------------
/aboutwindow.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Jorge Aparicio
3 | *
4 | * This file is part of ImageQ.
5 | *
6 | * ImageQ is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 |
11 | * ImageQ is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 |
16 | * You should have received a copy of the GNU General Public License
17 | * along with ImageQ. If not, see .
18 | */
19 |
20 | #pragma once
21 |
22 | #include
23 |
24 | namespace Ui {
25 | class AboutWindow;
26 | }
27 |
28 | class AboutWindow : public QMainWindow
29 | {
30 | Q_OBJECT
31 |
32 | public:
33 | explicit AboutWindow(QWidget *parent = 0);
34 | ~AboutWindow();
35 |
36 | private:
37 | Ui::AboutWindow *ui;
38 | };
39 |
--------------------------------------------------------------------------------
/aboutwindow.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | AboutWindow
4 |
5 |
6 |
7 | 0
8 | 0
9 | 309
10 | 346
11 |
12 |
13 |
14 | About
15 |
16 |
17 |
18 | -
19 |
20 |
-
21 |
22 |
23 | <center><h1>ImageQ</h1></center>
24 |
25 |
26 |
27 | -
28 |
29 |
30 | A Qt based image processing application.
31 |
32 |
33 | Qt::AlignCenter
34 |
35 |
36 |
37 | -
38 |
39 |
40 | Qt::Vertical
41 |
42 |
43 |
44 | 20
45 | 19
46 |
47 |
48 |
49 |
50 | -
51 |
52 |
53 | Copyright (C) 2012 Jorge Aparicio
54 |
55 |
56 | Qt::AlignCenter
57 |
58 |
59 |
60 | -
61 |
62 |
63 | <a href="mailto:jorge.aparicio.r@gmail.com"><jorge.aparicio.r@gmail.com></a>
64 |
65 |
66 | Qt::AlignCenter
67 |
68 |
69 |
70 | -
71 |
72 |
73 | Qt::Vertical
74 |
75 |
76 |
77 | 20
78 | 18
79 |
80 |
81 |
82 |
83 | -
84 |
85 |
86 | ImageQ is licensed under the:
87 |
88 |
89 | Qt::AlignCenter
90 |
91 |
92 |
93 | -
94 |
95 |
96 | <a href="http://www.gnu.org/copyleft/gpl.html">GNU General Public License (GPL) v3</a>
97 |
98 |
99 | Qt::AlignCenter
100 |
101 |
102 |
103 | -
104 |
105 |
106 | Qt::Vertical
107 |
108 |
109 |
110 | 20
111 | 18
112 |
113 |
114 |
115 |
116 | -
117 |
118 |
119 | <center>Source code can be found in this
120 | <a href="https://github.com/JorgeAparicio/ImageQ">
121 | repository</a></center>
122 |
123 |
124 | true
125 |
126 |
127 |
128 | -
129 |
130 |
131 | Qt::Vertical
132 |
133 |
134 |
135 | 20
136 | 40
137 |
138 |
139 |
140 |
141 | -
142 |
143 |
-
144 |
145 |
146 | Qt::Horizontal
147 |
148 |
149 |
150 | 40
151 | 20
152 |
153 |
154 |
155 |
156 | -
157 |
158 |
159 | OK
160 |
161 |
162 |
163 | -
164 |
165 |
166 | Qt::Horizontal
167 |
168 |
169 |
170 | 40
171 | 20
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
--------------------------------------------------------------------------------
/blurwindow.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Jorge Aparicio
3 | *
4 | * This file is part of ImageQ.
5 | *
6 | * ImageQ is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 |
11 | * ImageQ is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 |
16 | * You should have received a copy of the GNU General Public License
17 | * along with ImageQ. If not, see .
18 | */
19 |
20 | #include "blurwindow.h"
21 | #include "ui_blurwindow.h"
22 |
23 | #include "image.h"
24 |
25 | #include
26 |
27 | BlurWindow::BlurWindow(Image* image,
28 | QWidget *parent) :
29 | QMainWindow(parent),
30 | ui(new Ui::BlurWindow),
31 | image(image),
32 | abort(true)
33 | {
34 | ui->setupUi(this);
35 |
36 | image->backup();
37 |
38 | connect(this, SIGNAL(update()),
39 | image, SLOT(update()));
40 |
41 | this->setAttribute(Qt::WA_DeleteOnClose);
42 | this->setFixedSize(this->size());
43 |
44 | this->show();
45 |
46 | blur();
47 | }
48 |
49 | BlurWindow::~BlurWindow()
50 | {
51 | delete ui;
52 | }
53 |
54 | void BlurWindow::closeEvent(QCloseEvent *)
55 | {
56 | if (abort)
57 | image->undo();
58 | }
59 |
60 | void BlurWindow::on_cancelPushButton_clicked()
61 | {
62 | this->close();
63 | }
64 |
65 | void BlurWindow::on_okPushButton_clicked()
66 | {
67 | abort = false;
68 |
69 | this->close();
70 | }
71 |
72 | void BlurWindow::on_averageRadioButton_toggled(bool checked)
73 | {
74 | if (checked)
75 | blur();
76 | }
77 |
78 | void BlurWindow::on_gaussianRadioButton_toggled(bool checked)
79 | {
80 | if (checked)
81 | blur();
82 | }
83 |
84 | void BlurWindow::on_medianRadioButton_toggled(bool checked)
85 | {
86 | if (checked)
87 | blur();
88 | }
89 |
90 | void BlurWindow::on_sizeSpinBox_valueChanged(int)
91 | {
92 | blur();
93 | }
94 |
95 | void BlurWindow::blur()
96 | {
97 | int size = ui->sizeSpinBox->value();
98 |
99 | if (ui->averageRadioButton->isChecked()) {
100 | cv::blur(image->previous, image->current, cv::Size(size, size));
101 | } else if (ui->gaussianRadioButton->isChecked()) {
102 | cv::GaussianBlur(image->previous, image->current, cv::Size(size, size), 0);
103 | } else {
104 | cv::medianBlur(image->previous, image->current, size);
105 | }
106 |
107 | emit update();
108 | }
109 |
--------------------------------------------------------------------------------
/blurwindow.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Jorge Aparicio
3 | *
4 | * This file is part of ImageQ.
5 | *
6 | * ImageQ is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 |
11 | * ImageQ is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 |
16 | * You should have received a copy of the GNU General Public License
17 | * along with ImageQ. If not, see .
18 | */
19 |
20 | #pragma once
21 |
22 | #include
23 |
24 | class Image;
25 |
26 | namespace Ui {
27 | class BlurWindow;
28 | }
29 |
30 | class BlurWindow : public QMainWindow
31 | {
32 | Q_OBJECT
33 |
34 | public:
35 | explicit BlurWindow(Image* image,
36 | QWidget *parent = 0);
37 | ~BlurWindow();
38 |
39 | signals:
40 | void update();
41 |
42 | protected:
43 | void closeEvent(QCloseEvent *);
44 |
45 | private slots:
46 | void on_cancelPushButton_clicked();
47 | void on_okPushButton_clicked();
48 |
49 | void on_averageRadioButton_toggled(bool);
50 | void on_gaussianRadioButton_toggled(bool);
51 | void on_medianRadioButton_toggled(bool);
52 |
53 | void on_sizeSpinBox_valueChanged(int);
54 |
55 | private:
56 | Ui::BlurWindow *ui;
57 | Image* image;
58 | bool abort;
59 |
60 | void blur();
61 | };
62 |
--------------------------------------------------------------------------------
/blurwindow.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | BlurWindow
4 |
5 |
6 |
7 | 0
8 | 0
9 | 344
10 | 111
11 |
12 |
13 |
14 | Blur
15 |
16 |
17 |
18 | -
19 |
20 |
21 | Method
22 |
23 |
24 |
-
25 |
26 |
27 | Average
28 |
29 |
30 | true
31 |
32 |
33 |
34 | -
35 |
36 |
37 | Gaussian
38 |
39 |
40 |
41 | -
42 |
43 |
44 | Median
45 |
46 |
47 |
48 |
49 |
50 |
51 | -
52 |
53 |
-
54 |
55 |
56 | Kernel size:
57 |
58 |
59 |
60 | -
61 |
62 |
63 | 3
64 |
65 |
66 | 2
67 |
68 |
69 |
70 | -
71 |
72 |
73 | OK
74 |
75 |
76 |
77 | -
78 |
79 |
80 | Cancel
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/cannywindow.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Jorge Aparicio
3 | *
4 | * This file is part of ImageQ.
5 | *
6 | * ImageQ is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 |
11 | * ImageQ is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 |
16 | * You should have received a copy of the GNU General Public License
17 | * along with ImageQ. If not, see .
18 | */
19 |
20 | #include "cannywindow.h"
21 | #include "ui_cannywindow.h"
22 |
23 | #include "image.h"
24 |
25 | #include
26 |
27 | CannyWindow::CannyWindow(Image* image,
28 | QWidget *parent) :
29 | QMainWindow(parent),
30 | ui(new Ui::CannyWindow),
31 | image(image),
32 | abort(true)
33 | {
34 | ui->setupUi(this);
35 |
36 | image->backup();
37 |
38 | connect(this, SIGNAL(update()),
39 | image, SLOT(update()));
40 |
41 | this->setAttribute(Qt::WA_DeleteOnClose);
42 |
43 | ui->manualGroupBox->hide();
44 | this->adjustSize();
45 | this->setFixedSize(this->size());
46 |
47 | this->show();
48 |
49 | canny();
50 | }
51 |
52 | CannyWindow::~CannyWindow()
53 | {
54 | delete ui;
55 | }
56 |
57 | void CannyWindow::closeEvent(QCloseEvent *)
58 | {
59 | if (abort)
60 | image->undo();
61 | }
62 |
63 | void CannyWindow::on_cancelPushButton_clicked()
64 | {
65 | this->close();
66 | }
67 |
68 | void CannyWindow::on_okPushButton_clicked()
69 | {
70 | abort = false;
71 |
72 | this->close();
73 | }
74 |
75 | void CannyWindow::on_l1RadioButton_toggled(bool checked)
76 | {
77 | if (checked)
78 | canny();
79 | }
80 |
81 | void CannyWindow::on_l2RadioButton_toggled(bool checked)
82 | {
83 | if (checked)
84 | canny();
85 | }
86 |
87 | void CannyWindow::on_manualRadioButton_toggled(bool checked)
88 | {
89 | if (checked) {
90 | ui->manualGroupBox->show();
91 |
92 | canny();
93 | } else
94 | ui->manualGroupBox->hide();
95 | }
96 |
97 | void CannyWindow::on_meanRadioButton_toggled(bool checked)
98 | {
99 | if (checked)
100 | canny();
101 | }
102 |
103 | void CannyWindow::on_medianRadioButton_toggled(bool checked)
104 | {
105 | if (checked)
106 | canny();
107 | }
108 |
109 | void CannyWindow::on_semiAutomaticRadioButton_toggled(bool checked)
110 | {
111 | if (checked) {
112 | ui->semiAutomaticGroupBox->show();
113 |
114 | canny();
115 | } else
116 | ui->semiAutomaticGroupBox->hide();
117 | }
118 |
119 | void CannyWindow::on_maximumSlider_valueChanged(int value)
120 | {
121 | if (ui->minimumSlider->value() > value)
122 | ui->minimumSlider->setValue(value);
123 |
124 | canny();
125 | }
126 |
127 | void CannyWindow::on_minimumSlider_valueChanged(int value)
128 | {
129 | if (ui->maximumSlider->value() < value)
130 | ui->maximumSlider->setValue(value);
131 |
132 | canny();
133 | }
134 |
135 |
136 | void CannyWindow::on_sizeSpinBox_valueChanged(int)
137 | {
138 | canny();
139 | }
140 |
141 | void CannyWindow::canny()
142 | {
143 | int size = ui->sizeSpinBox->value();
144 | bool l2norm = ui->l2RadioButton->isChecked();
145 |
146 | if (ui->manualRadioButton->isChecked()) {
147 | cv::Canny(image->previous,
148 | image->current,
149 | ui->minimumSlider->value(),
150 | ui->maximumSlider->value(),
151 | size,
152 | l2norm);
153 | } else if (ui->meanRadioButton->isChecked()) {
154 | double mean = calculateMean();
155 |
156 | cv::Canny(image->previous,
157 | image->current,
158 | 2 * mean / 3,
159 | 4 * mean / 3,
160 | size,
161 | l2norm);
162 | } else {
163 | double median = calculateMedian();
164 |
165 | cv::Canny(image->previous,
166 | image->current,
167 | 2 * median / 3,
168 | 4 * median / 3,
169 | size,
170 | l2norm);
171 | }
172 |
173 | emit update();
174 | }
175 |
176 | double CannyWindow::calculateMean()
177 | {
178 | return cv::mean(image->previous)[0];
179 | }
180 |
181 | double CannyWindow::calculateMedian()
182 | {
183 | cv::Mat histogram;
184 | int acc = 0;
185 | int const size = image->previous.rows * image->previous.cols;
186 |
187 | std::vector images;
188 | std::vector channels;
189 | std::vector histSize;
190 | std::vector ranges;
191 |
192 | images.push_back(image->previous);
193 | channels.push_back(0);
194 | histSize.push_back(256);
195 | ranges.push_back(0);
196 | ranges.push_back(256);
197 |
198 | cv::calcHist(images, channels, cv::Mat(), histogram, histSize, ranges);
199 |
200 | for (int i = 0; i < 256; i++) {
201 | acc += histogram.at(i);
202 | if (acc > size / 2)
203 | return i;
204 | }
205 |
206 | return 0;
207 | }
208 |
--------------------------------------------------------------------------------
/cannywindow.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Jorge Aparicio
3 | *
4 | * This file is part of ImageQ.
5 | *
6 | * ImageQ is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 |
11 | * ImageQ is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 |
16 | * You should have received a copy of the GNU General Public License
17 | * along with ImageQ. If not, see .
18 | */
19 |
20 | #pragma once
21 |
22 | #include
23 |
24 | class Image;
25 |
26 | namespace Ui {
27 | class CannyWindow;
28 | }
29 |
30 | class CannyWindow : public QMainWindow
31 | {
32 | Q_OBJECT
33 |
34 | public:
35 | explicit CannyWindow(Image* image,
36 | QWidget *parent = 0);
37 | ~CannyWindow();
38 |
39 | signals:
40 | void update();
41 |
42 | protected:
43 | void closeEvent(QCloseEvent *);
44 |
45 | private slots:
46 | void on_cancelPushButton_clicked();
47 | void on_okPushButton_clicked();
48 |
49 | void on_l1RadioButton_toggled(bool);
50 | void on_l2RadioButton_toggled(bool);
51 | void on_manualRadioButton_toggled(bool);
52 | void on_meanRadioButton_toggled(bool);
53 | void on_medianRadioButton_toggled(bool);
54 | void on_semiAutomaticRadioButton_toggled(bool);
55 |
56 | void on_maximumSlider_valueChanged(int);
57 | void on_minimumSlider_valueChanged(int);
58 | void on_sizeSpinBox_valueChanged(int);
59 |
60 | private:
61 | Ui::CannyWindow *ui;
62 | Image* image;
63 | bool abort;
64 |
65 | void canny();
66 | double calculateMean();
67 | double calculateMedian();
68 | };
69 |
--------------------------------------------------------------------------------
/cannywindow.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | CannyWindow
4 |
5 |
6 |
7 | 0
8 | 0
9 | 199
10 | 511
11 |
12 |
13 |
14 | Canny
15 |
16 |
17 |
18 | -
19 |
20 |
21 | Mode
22 |
23 |
24 |
-
25 |
26 |
27 | Semi-automatic
28 |
29 |
30 | true
31 |
32 |
33 |
34 | -
35 |
36 |
37 | Manual
38 |
39 |
40 |
41 |
42 |
43 |
44 | -
45 |
46 |
47 | Threshold
48 |
49 |
50 |
-
51 |
52 |
53 | Mean
54 |
55 |
56 | true
57 |
58 |
59 |
60 | -
61 |
62 |
63 | Median
64 |
65 |
66 |
67 |
68 |
69 |
70 | -
71 |
72 |
73 | Threshold
74 |
75 |
76 |
-
77 |
78 |
79 | 255
80 |
81 |
82 | 255
83 |
84 |
85 | Qt::Horizontal
86 |
87 |
88 |
89 | -
90 |
91 |
92 | 255
93 |
94 |
95 | Qt::Horizontal
96 |
97 |
98 |
99 |
100 |
101 |
102 | -
103 |
104 |
105 | Norm
106 |
107 |
108 |
-
109 |
110 |
111 | L1 (faster)
112 |
113 |
114 | true
115 |
116 |
117 |
118 | -
119 |
120 |
121 | L2 (more accurate)
122 |
123 |
124 |
125 |
126 |
127 |
128 | -
129 |
130 |
-
131 |
132 |
133 | Kernel size:
134 |
135 |
136 |
137 | -
138 |
139 |
140 | 3
141 |
142 |
143 | 7
144 |
145 |
146 | 2
147 |
148 |
149 |
150 |
151 |
152 | -
153 |
154 |
-
155 |
156 |
157 | OK
158 |
159 |
160 |
161 | -
162 |
163 |
164 | Cancel
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
182 |
183 |
184 |
185 |
186 |
187 |
--------------------------------------------------------------------------------
/gradientwindow.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Jorge Aparicio
3 | *
4 | * This file is part of ImageQ.
5 | *
6 | * ImageQ is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 |
11 | * ImageQ is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 |
16 | * You should have received a copy of the GNU General Public License
17 | * along with ImageQ. If not, see .
18 | */
19 |
20 | #include "gradientwindow.h"
21 | #include "ui_gradientwindow.h"
22 |
23 | #include "image.h"
24 |
25 | #include
26 |
27 | GradientWindow::GradientWindow(Image* image,
28 | QWidget *parent) :
29 | QMainWindow(parent),
30 | ui(new Ui::GradientWindow),
31 | image(image),
32 | abort(true)
33 | {
34 | ui->setupUi(this);
35 |
36 | image->backup();
37 |
38 | connect(this, SIGNAL(update()),
39 | image, SLOT(update()));
40 |
41 | this->setAttribute(Qt::WA_DeleteOnClose);
42 | this->setFixedSize(this->size());
43 |
44 | this->show();
45 |
46 | gradient();
47 | }
48 |
49 | GradientWindow::~GradientWindow()
50 | {
51 | delete ui;
52 | }
53 |
54 | void GradientWindow::closeEvent(QCloseEvent *)
55 | {
56 | if (abort)
57 | image->undo();
58 | }
59 |
60 | void GradientWindow::on_cancelPushButton_clicked()
61 | {
62 | this->close();
63 | }
64 |
65 | void GradientWindow::on_okPushButton_clicked()
66 | {
67 | abort = false;
68 |
69 | this->close();
70 | }
71 |
72 | void GradientWindow::on_absoluteCheckBox_toggled(bool)
73 | {
74 | gradient();
75 | }
76 |
77 | void GradientWindow::on_laplacianRadioButton_toggled(bool checked)
78 | {
79 | ui->magnitudeCheckBox->setDisabled(checked);
80 | ui->xSpinBox->setDisabled(checked);
81 | ui->ySpinBox->setDisabled(checked);
82 |
83 | if (checked) {
84 | ui->magnitudeCheckBox->setChecked(false);
85 | ui->sizeSpinBox->setMinimum(1);
86 |
87 | gradient();
88 | } else {
89 | ui->sizeSpinBox->setMinimum(3);
90 | }
91 | }
92 |
93 | void GradientWindow::on_magnitudeCheckBox_toggled(bool checked)
94 | {
95 | ui->absoluteCheckBox->setDisabled(checked);
96 | ui->xSpinBox->setDisabled(checked);
97 | ui->ySpinBox->setDisabled(checked);
98 |
99 | if (checked) {
100 | ui->absoluteCheckBox->setChecked(false);
101 | }
102 |
103 | gradient();
104 | }
105 |
106 | void GradientWindow::on_scharrRadioButton_toggled(bool checked)
107 | {
108 | ui->sizeSpinBox->setDisabled(checked);
109 |
110 | if (checked) {
111 | ui->xSpinBox->setMaximum(1);
112 | ui->ySpinBox->setMaximum(1);
113 |
114 | ui->sizeSpinBox->setValue(3);
115 |
116 | ui->xSpinBox->setValue(1);
117 |
118 | gradient();
119 | }
120 | }
121 |
122 | void GradientWindow::on_sobelRadioButton_toggled(bool checked)
123 | {
124 | if (checked) {
125 | ui->xSpinBox->setMaximum(2);
126 | ui->ySpinBox->setMaximum(2);
127 |
128 | gradient();
129 | }
130 | }
131 |
132 | void GradientWindow::on_xSpinBox_valueChanged(int value)
133 | {
134 | if (ui->sobelRadioButton->isChecked()) {
135 | if (value)
136 | ui->ySpinBox->setMinimum(0);
137 | else
138 | ui->ySpinBox->setMinimum(1);
139 | } else {
140 | ui->ySpinBox->setMinimum(0);
141 | ui->ySpinBox->setValue(1 - value);
142 | }
143 |
144 | gradient();
145 | }
146 |
147 | void GradientWindow::on_ySpinBox_valueChanged(int value)
148 | {
149 | if (ui->sobelRadioButton->isChecked()) {
150 | if (value)
151 | ui->xSpinBox->setMinimum(0);
152 | else
153 | ui->xSpinBox->setMinimum(1);
154 | } else {
155 | ui->xSpinBox->setMinimum(0);
156 | ui->xSpinBox->setValue(1 - value);
157 | }
158 |
159 | gradient();
160 | }
161 |
162 | void GradientWindow::on_sizeSpinBox_valueChanged(int)
163 | {
164 | gradient();
165 | }
166 |
167 | void GradientWindow::gradient()
168 | {
169 | cv::Mat tmp;
170 | int size = ui->sizeSpinBox->value();
171 | int dx = ui->xSpinBox->value();
172 | int dy = ui->ySpinBox->value();
173 |
174 | image->previous.convertTo(tmp, CV_32F, 1.0/255.0);
175 |
176 | if (ui->laplacianRadioButton->isChecked()) {
177 | cv::Laplacian(tmp, tmp, CV_32F, size);
178 | } else if (ui->magnitudeCheckBox->isChecked()) {
179 | cv::Mat derivative;
180 | cv::Mat magnitude = cv::Mat::zeros(tmp.rows, tmp.cols, CV_32F);
181 |
182 | if (ui->sobelRadioButton->isChecked())
183 | cv::Sobel(tmp, derivative, CV_32F, 1, 0, size);
184 | else
185 | cv::Scharr(tmp, derivative, CV_32F, 1, 0);
186 |
187 | cv::accumulateSquare(derivative, magnitude);
188 |
189 | if (ui->sobelRadioButton->isChecked())
190 | cv::Sobel(tmp, derivative, CV_32F, 0, 1, size);
191 | else
192 | cv::Scharr(tmp, derivative, CV_32F, 0, 1);
193 |
194 | cv::accumulateSquare(derivative, magnitude);
195 |
196 | cv::sqrt(magnitude, tmp);
197 | } else if (ui->scharrRadioButton->isChecked()) {
198 | cv::Scharr(tmp, tmp, CV_32F, dx, dy);
199 | } else if (ui->sobelRadioButton->isChecked()) {
200 | cv::Sobel(tmp, tmp, CV_32F, dx, dy, size);
201 | }
202 |
203 | if (ui->absoluteCheckBox->isChecked())
204 | tmp = cv::abs(tmp);
205 |
206 | cv::normalize(tmp, tmp, 0, 1, cv::NORM_MINMAX);
207 |
208 | tmp.convertTo(image->current, CV_8U, 255.0);
209 |
210 | emit update();
211 | }
212 |
--------------------------------------------------------------------------------
/gradientwindow.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Jorge Aparicio
3 | *
4 | * This file is part of ImageQ.
5 | *
6 | * ImageQ is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 |
11 | * ImageQ is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 |
16 | * You should have received a copy of the GNU General Public License
17 | * along with ImageQ. If not, see .
18 | */
19 |
20 | #pragma once
21 |
22 | #include
23 |
24 | class Image;
25 |
26 | namespace Ui {
27 | class GradientWindow;
28 | }
29 |
30 | class GradientWindow : public QMainWindow
31 | {
32 | Q_OBJECT
33 |
34 | public:
35 | explicit GradientWindow(Image* image,
36 | QWidget *parent = 0);
37 | ~GradientWindow();
38 |
39 | signals:
40 | void update();
41 |
42 | protected:
43 | void closeEvent(QCloseEvent *);
44 |
45 | private slots:
46 | void on_cancelPushButton_clicked();
47 | void on_okPushButton_clicked();
48 |
49 | void on_absoluteCheckBox_toggled(bool);
50 | void on_laplacianRadioButton_toggled(bool);
51 | void on_magnitudeCheckBox_toggled(bool);
52 | void on_scharrRadioButton_toggled(bool);
53 | void on_sobelRadioButton_toggled(bool);
54 |
55 | void on_sizeSpinBox_valueChanged(int);
56 | void on_xSpinBox_valueChanged(int);
57 | void on_ySpinBox_valueChanged(int);
58 |
59 | private:
60 | Ui::GradientWindow *ui;
61 | Image* image;
62 | bool abort;
63 |
64 | void gradient();
65 | };
66 |
--------------------------------------------------------------------------------
/gradientwindow.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | GradientWindow
4 |
5 |
6 |
7 | 0
8 | 0
9 | 196
10 | 364
11 |
12 |
13 |
14 | Gradient
15 |
16 |
17 |
18 | -
19 |
20 |
21 | Method
22 |
23 |
24 |
-
25 |
26 |
27 | Laplacian
28 |
29 |
30 | false
31 |
32 |
33 |
34 | -
35 |
36 |
37 | Scharr
38 |
39 |
40 |
41 | -
42 |
43 |
44 | Sobel
45 |
46 |
47 | true
48 |
49 |
50 |
51 |
52 |
53 |
54 | -
55 |
56 |
57 | Direction
58 |
59 |
60 |
-
61 |
62 |
-
63 |
64 |
65 | d/dX
66 |
67 |
68 | Qt::AlignCenter
69 |
70 |
71 |
72 | -
73 |
74 |
75 | 1
76 |
77 |
78 | 2
79 |
80 |
81 |
82 |
83 |
84 | -
85 |
86 |
-
87 |
88 |
89 | d/dY
90 |
91 |
92 | Qt::AlignCenter
93 |
94 |
95 |
96 | -
97 |
98 |
99 | 0
100 |
101 |
102 | 2
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 | -
112 |
113 |
114 | Absolute
115 |
116 |
117 |
118 | -
119 |
120 |
121 | Magnitude
122 |
123 |
124 |
125 | -
126 |
127 |
-
128 |
129 |
130 | Kernel size:
131 |
132 |
133 |
134 | -
135 |
136 |
137 | 3
138 |
139 |
140 | 7
141 |
142 |
143 | 2
144 |
145 |
146 |
147 |
148 |
149 | -
150 |
151 |
-
152 |
153 |
154 | OK
155 |
156 |
157 |
158 | -
159 |
160 |
161 | Cancel
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
--------------------------------------------------------------------------------
/histogram.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Jorge Aparicio
3 | *
4 | * This file is part of ImageQ.
5 | *
6 | * ImageQ is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 |
11 | * ImageQ is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 |
16 | * You should have received a copy of the GNU General Public License
17 | * along with ImageQ. If not, see .
18 | */
19 |
20 | #include "histogram.h"
21 |
22 | #include
23 | #include
24 |
25 | Histogram::Histogram(cv::Mat const& image, int const numberOfBins)
26 | {
27 | cv::Mat histogram;
28 |
29 | std::vector images;
30 | std::vector channels;
31 | std::vector histSize;
32 | std::vector ranges;
33 |
34 | images.push_back(image);
35 | channels.push_back(0);
36 | histSize.push_back(numberOfBins);
37 | ranges.push_back(0);
38 | ranges.push_back(256);
39 |
40 | cv::calcHist(images, channels, cv::Mat(), histogram, histSize, ranges);
41 |
42 | QVector samples(numberOfBins);
43 |
44 | for (int i = 0; i < numberOfBins; i++)
45 | samples[i] = QwtIntervalSample(histogram.at(i),
46 | QwtInterval(i, i + 1));
47 |
48 | QColor color(Qt::blue);
49 |
50 | color.setAlpha(0);
51 | setPen(QPen(color));
52 | color.setAlpha(96);
53 | setBrush(QBrush(color));
54 |
55 | setData(new QwtIntervalSeriesData(samples));
56 |
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/histogram.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Jorge Aparicio
3 | *
4 | * This file is part of ImageQ.
5 | *
6 | * ImageQ is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 |
11 | * ImageQ is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 |
16 | * You should have received a copy of the GNU General Public License
17 | * along with ImageQ. If not, see .
18 | */
19 |
20 | #pragma once
21 |
22 | #include
23 |
24 | namespace cv {
25 | class Mat;
26 | }
27 |
28 | class Histogram : public QwtPlotHistogram
29 | {
30 | public:
31 | Histogram(cv::Mat const&, int const);
32 | };
33 |
--------------------------------------------------------------------------------
/histogramwindow.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Jorge Aparicio
3 | *
4 | * This file is part of ImageQ.
5 | *
6 | * ImageQ is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 |
11 | * ImageQ is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 |
16 | * You should have received a copy of the GNU General Public License
17 | * along with ImageQ. If not, see .
18 | */
19 |
20 | #include "histogramwindow.h"
21 | #include "ui_histogramwindow.h"
22 |
23 | HistogramWindow::HistogramWindow(cv::Mat const& image, QWidget *parent) :
24 | QMainWindow(parent),
25 | ui(new Ui::HistogramWindow),
26 | histogram(image, 256)
27 | {
28 | ui->setupUi(this);
29 |
30 | histogram.attach(ui->histogramPlot);
31 |
32 | ui->histogramPlot->setAxisAutoScale(QwtPlot::xBottom, false);
33 | ui->histogramPlot->setAxisScale(QwtPlot::xBottom, 0, 256);
34 |
35 | ui->histogramPlot->enableAxis(QwtPlot::xBottom, false);
36 | ui->histogramPlot->enableAxis(QwtPlot::yLeft, false);
37 |
38 | ui->histogramPlot->setFixedSize(480, 200);
39 | this->adjustSize();
40 |
41 | this->setAttribute(Qt::WA_DeleteOnClose);
42 | this->setFixedSize(this->size());
43 |
44 | this->show();
45 | }
46 |
47 | HistogramWindow::~HistogramWindow()
48 | {
49 | delete ui;
50 | }
51 |
--------------------------------------------------------------------------------
/histogramwindow.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Jorge Aparicio
3 | *
4 | * This file is part of ImageQ.
5 | *
6 | * ImageQ is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 |
11 | * ImageQ is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 |
16 | * You should have received a copy of the GNU General Public License
17 | * along with ImageQ. If not, see .
18 | */
19 |
20 | #pragma once
21 |
22 | #include
23 |
24 | #include "histogram.h"
25 |
26 | namespace cv {
27 | class Mat;
28 | }
29 |
30 | namespace Ui {
31 | class HistogramWindow;
32 | }
33 |
34 | class HistogramWindow : public QMainWindow
35 | {
36 | Q_OBJECT
37 |
38 | public:
39 | explicit HistogramWindow(cv::Mat const&, QWidget *parent = 0);
40 | ~HistogramWindow();
41 |
42 | private:
43 | Ui::HistogramWindow *ui;
44 | Histogram histogram;
45 | };
46 |
--------------------------------------------------------------------------------
/histogramwindow.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | HistogramWindow
4 |
5 |
6 |
7 | 0
8 | 0
9 | 50
10 | 50
11 |
12 |
13 |
14 | Histogram
15 |
16 |
17 |
18 | -
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | QwtPlot
27 | QFrame
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/image.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Jorge Aparicio
3 | *
4 | * This file is part of ImageQ.
5 | *
6 | * ImageQ is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 |
11 | * ImageQ is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 |
16 | * You should have received a copy of the GNU General Public License
17 | * along with ImageQ. If not, see .
18 | */
19 |
20 | #include "image.h"
21 | #include "ui_image.h"
22 |
23 | #include "mat2qimage.h"
24 | #include "textlistwindow.h"
25 |
26 | #include
27 | #include
28 |
29 | #include
30 | #include
31 |
32 | Image::Image(QString pathToImage, QWidget *parent) :
33 | QWidget(parent),
34 | ui(new Ui::Image),
35 | first(cv::imread(pathToImage.toStdString()))
36 | {
37 | initialize();
38 | }
39 |
40 | Image::Image(cv::Mat const& image, QWidget *parent) :
41 | QWidget(parent),
42 | ui(new Ui::Image),
43 | first(image)
44 | {
45 | initialize();
46 | }
47 |
48 | void Image::initialize()
49 | {
50 | ui->setupUi(this);
51 |
52 | distances = 0;
53 | areas = 0;
54 |
55 | first.copyTo(current);
56 |
57 | color = QColor(Qt::red);
58 |
59 | mousePressed = false;
60 | selectionMode = None;
61 | scale = 1;
62 | unit = 'm';
63 |
64 | connect(ui->imageLabel, SIGNAL(mouseHover(QPoint)),
65 | this, SLOT(pixelInfo(QPoint)));
66 |
67 | connect(ui->imageLabel, SIGNAL(mouseHover(QPoint)),
68 | this, SLOT(mouseMove(QPoint)));
69 |
70 | connect(ui->imageLabel, SIGNAL(mouseDoubleClick(QPoint)),
71 | this, SLOT(mouseDoubleClick(QPoint)));
72 |
73 | connect(ui->imageLabel, SIGNAL(mousePress(QPoint)),
74 | this, SLOT(mousePress(QPoint)));
75 |
76 | connect(ui->imageLabel, SIGNAL(mouseRelease(QPoint)),
77 | this, SLOT(mouseRelease(QPoint)));
78 |
79 | connect(ui->imageLabel, SIGNAL(resized()),
80 | this, SLOT(rescale()));
81 |
82 | connect(ui->scrollArea->horizontalScrollBar(), SIGNAL(rangeChanged(int,int)),
83 | this, SLOT(rescale()));
84 |
85 | connect(ui->scrollArea->verticalScrollBar(), SIGNAL(rangeChanged(int,int)),
86 | this, SLOT(rescale()));
87 | }
88 |
89 | Image::~Image()
90 | {
91 | delete ui;
92 | distances->close();
93 | areas->close();
94 |
95 | // FIXME: Is this necessary?
96 | current.release();
97 | previous.release();
98 | first.release();
99 | }
100 |
101 | void Image::backup()
102 | {
103 | current.copyTo(previous);
104 | }
105 |
106 | void Image::HSV(std::vector& hsv) const
107 | {
108 | cv::Mat tmp;
109 |
110 | cv::cvtColor(current, tmp, CV_BGR2HSV);
111 |
112 | cv::split(tmp, hsv);
113 | }
114 |
115 | void Image::revert()
116 | {
117 | first.copyTo(current);
118 | previous.release();
119 |
120 | update();
121 | }
122 |
123 | void Image::RGB(std::vector& rgb) const
124 | {
125 | cv::Mat tmp;
126 |
127 | cv::cvtColor(current, tmp, CV_BGR2RGB);
128 |
129 | cv::split(tmp, rgb);
130 | }
131 |
132 | void Image::undo()
133 | {
134 | if (previous.data != 0) {
135 | previous.copyTo(current);
136 | update();
137 | }
138 | }
139 |
140 | void Image::display()
141 | {
142 | pixmap = QPixmap::fromImage(Mat2QImage(current));
143 |
144 | if (ui->fitToScreenCheckBox->isChecked())
145 | pixmap = pixmap.scaled(ui->imageLabel->size(), Qt::KeepAspectRatio);
146 |
147 | loadOverlay();
148 |
149 | if (ui->withOverlayCheckBox->isChecked())
150 | ui->imageLabel->setPixmap(overlayedPixmap);
151 | else
152 | ui->imageLabel->setPixmap(pixmap);
153 | }
154 |
155 | void Image::pixelInfo(QPoint p) const
156 | {
157 | remapPoint(p);
158 |
159 | ui->xLabel->setText(QString::number(p.x()));
160 | ui->yLabel->setText(QString::number(p.y()));
161 |
162 | switch(current.channels()) {
163 | case 1:
164 | ui->valueLabel->setText(QString::number(current.at(p.y(), p.x())));
165 | break;
166 | case 3:
167 | cv::Vec3b bgr = current.at(p.y(), p.x());
168 | ui->valueLabel->setText("(" + QString::number(bgr[2]) +
169 | ", " + QString::number(bgr[1]) +
170 | ", " + QString::number(bgr[0]) + ")");
171 | break;
172 | }
173 | }
174 |
175 | void Image::mouseDoubleClick(QPoint p)
176 | {
177 | remapPoint(p);
178 |
179 | switch (selectionMode) {
180 | case None:
181 | break;
182 |
183 | case Line:
184 | emit lineSelected(QLine());
185 | break;
186 |
187 | case Distance:
188 | break;
189 |
190 | case Rectangle:
191 | if (rect.topLeft().x() <= p.x() && p.x() <= rect.bottomRight().x() &&
192 | rect.topLeft().y() <= p.y() && p.y() <= rect.bottomRight().y()) {
193 | emit rectangleSelected(rect);
194 | } else {
195 | emit rectangleSelected(QRect());
196 | }
197 | overlay.rect.pop_back();
198 | break;
199 | }
200 |
201 | setSelectionMode(None);
202 |
203 | p1 = QPoint(-1, -1);
204 | p2 = QPoint(-1, -1);
205 | }
206 |
207 | void Image::mouseMove(QPoint p)
208 | {
209 | if (selectionMode != None) {
210 | remapPoint(p);
211 |
212 | if (mousePressed) {
213 | p2 = p;
214 |
215 | tempPixmap = overlayedPixmap;
216 | color.setAlpha(128);
217 |
218 | QPainter painter(&tempPixmap);
219 | painter.setPen(color);
220 |
221 | switch (selectionMode) {
222 | case Rectangle:
223 | {
224 | QRect rect;
225 |
226 | if (p1.x() < p2.x() || p1.y() < p2.y())
227 | rect = QRect(p1 * pixmap.width() / current.cols,
228 | p2 * pixmap.height() / current.rows);
229 | else
230 | rect = QRect(p2 * pixmap.width() / current.cols,
231 | p1 * pixmap.height() / current.rows);
232 |
233 | painter.drawRect(rect);
234 | color.setAlpha(64);
235 | painter.fillRect(rect, color);
236 | break;
237 | }
238 |
239 | case Distance:
240 | case Line:
241 | {
242 | QLine line(p1 * pixmap.width() / current.cols,
243 | p2 * pixmap.height() / current.rows);
244 |
245 | painter.drawLine(line);
246 | break;
247 | }
248 |
249 | case None:
250 | break;
251 | }
252 |
253 | ui->imageLabel->setPixmap(tempPixmap);
254 | }
255 | }
256 | }
257 |
258 | void Image::mousePress(QPoint p)
259 | {
260 | if (selectionMode != None) {
261 | remapPoint(p);
262 |
263 | if (selectionMode == Rectangle)
264 | clearOverlay();
265 |
266 | mousePressed = true;
267 |
268 | p1 = p;
269 | p2 = QPoint(-1, -1);
270 | }
271 | }
272 |
273 | void Image::mouseRelease(QPoint p)
274 | {
275 | if (selectionMode != None) {
276 | remapPoint(p);
277 |
278 | mousePressed = false;
279 |
280 | p2 = p;
281 |
282 | overlayedPixmap = tempPixmap;
283 |
284 | if (p1.x() >= 0 && p1.y() >= 0 && (p1.x() != p2.x() || p1.y() != p2.y()))
285 | switch (selectionMode) {
286 | case None:
287 | break;
288 |
289 | case Line:
290 | overlay.line.append(QLine(p1, p2));
291 | emit lineSelected(QLine(p1, p2));
292 | break;
293 |
294 | case Distance:
295 | {
296 | int N = distances->size() + 1;
297 | float distance = sqrt(pow(p1.x() - p2.x(), 2) +
298 | pow(p1.y() - p2.y(), 2)) * scale;
299 | Text text;
300 | text.p = (p1 + p2) / 2;
301 | text.s = QString::number(N);
302 |
303 | overlay.line.append(QLine(p1, p2));
304 | overlay.text.append(text);
305 |
306 | QPainter p(&overlayedPixmap);
307 | color.setAlpha(128);
308 | p.setPen(QPen(color));
309 | p.drawText((text.p * pixmap.width()) / current.cols,
310 | text.s);
311 |
312 | ui->imageLabel->setPixmap(overlayedPixmap);
313 | tempPixmap = overlayedPixmap;
314 | distances->append(QString::number(N) + '\t' +
315 | QString::number(distance) + '\t' +
316 | unit);
317 | break;
318 | }
319 |
320 | case Rectangle:
321 | emit status("Double-click inside the area to crop.");
322 |
323 | if (p1.x() < p2.x() || p1.y() < p2.y()) {
324 | rect = QRect(p1, p2);
325 | overlay.rect.append(QRect(p1, p2));
326 | } else {
327 | rect = QRect(p2, p1);
328 | overlay.rect.append(QRect(p2, p1));
329 | }
330 | break;
331 | }
332 | }
333 | }
334 |
335 | void Image::on_fitToScreenCheckBox_toggled(bool checked)
336 | {
337 | if (checked &&
338 | (ui->scrollArea->horizontalScrollBar()->maximum() != 0 ||
339 | ui->scrollArea->verticalScrollBar()->maximum() != 0))
340 | ui->imageLabel->clear();
341 | else
342 | display();
343 | }
344 |
345 | void Image::rescale()
346 | {
347 | if (ui->fitToScreenCheckBox->isChecked()) {
348 | if (ui->scrollArea->horizontalScrollBar()->maximum() == 0 &&
349 | ui->scrollArea->verticalScrollBar()->maximum() == 0) {
350 | if (pixmap.width() != ui->imageLabel->width() &&
351 | pixmap.height() != ui->imageLabel->height()) {
352 | display();
353 | }
354 | } else if (pixmap.height() != 0 && pixmap.width() != 0) {
355 | ui->imageLabel->clear();
356 | pixmap = QPixmap();
357 | }
358 | }
359 | }
360 |
361 | void Image::setSelectionMode(SelectionMode mode)
362 | {
363 | selectionMode = mode;
364 | ui->withOverlayCheckBox->setChecked(true);
365 |
366 | switch (mode) {
367 | case None:
368 | emit exitSelectionMode();
369 | emit status("");
370 | break;
371 |
372 | case Distance:
373 | if (distances == 0) {
374 | clearOverlay();
375 |
376 | distances = new TextListWindow("Distances",
377 | "N\tLength\tUnit",
378 | this);
379 | }
380 |
381 | connect(distances, SIGNAL(destroyed()),
382 | this, SLOT(detachDistancesWindows()));
383 | case Line:
384 | overlayedPixmap = pixmap;
385 | tempPixmap = pixmap;
386 | emit status("Drag-draw a line. Double-click to exit.");
387 | break;
388 |
389 | case Rectangle:
390 | clearOverlay();
391 | overlayedPixmap = pixmap;
392 | tempPixmap = pixmap;
393 | emit status("Drag-select an area.");
394 | break;
395 | }
396 | }
397 |
398 | void Image::update()
399 | {
400 | double min, max;
401 | cv::minMaxLoc(current, &min, &max);
402 |
403 | ui->minimumLabel->setText(QString::number(min));
404 | ui->maximumLabel->setText(QString::number(max));
405 |
406 | ui->heightLabel->setText(QString::number(current.rows));
407 | ui->widthLabel->setText(QString::number(current.cols));
408 |
409 | switch (current.channels()) {
410 | case 1:
411 | ui->channelLabel->setText("1");
412 | break;
413 | case 3:
414 | ui->channelLabel->setText("3");
415 | break;
416 | }
417 |
418 | switch (current.depth()) {
419 | case CV_8U:
420 | ui->depthLabel->setText("8 bits");
421 | break;
422 | case CV_32F:
423 | ui->depthLabel->setText("32 bits");
424 | break;
425 | }
426 |
427 | clearOverlay();
428 |
429 | display();
430 | }
431 |
432 | void Image::clearOverlay()
433 | {
434 | overlay.line.clear();
435 | overlay.text.clear();
436 | overlay.rect.clear();
437 |
438 | if (distances)
439 | distances->close();
440 |
441 | if (areas)
442 | areas->close();
443 |
444 | ui->imageLabel->setPixmap(pixmap);
445 | overlayedPixmap = pixmap;
446 | }
447 |
448 | void Image::loadOverlay()
449 | {
450 | overlayedPixmap = pixmap;
451 | QPainter p(&overlayedPixmap);
452 |
453 | color.setAlpha(128);
454 | p.setPen(color);
455 | color.setAlpha(64);
456 | for (int i = 0; i < overlay.line.size(); i++) {
457 | QPoint p1 = overlay.line.at(i).p1();
458 | QPoint p2 = overlay.line.at(i).p2();
459 |
460 | p1 = p1 * pixmap.width() / current.cols;
461 | p2 = p2 * pixmap.width() / current.cols;
462 |
463 | p.drawLine(QLine(p1, p2));
464 | }
465 |
466 | for (int i = 0; i < overlay.text.size(); i++) {
467 | QPoint p1 = overlay.text.at(i).p;
468 |
469 | p1 = p1 * pixmap.width() / current.cols;
470 |
471 | p.drawText(p1, overlay.text.at(i).s);
472 | }
473 |
474 | for (int i = 0; i < overlay.rect.size(); i++) {
475 | QPoint p1 = overlay.rect.at(i).topLeft();
476 | QPoint p2 = overlay.rect.at(i).bottomRight();
477 |
478 | p1 = p1 * pixmap.width() / current.cols;
479 | p2 = p2 * pixmap.width() / current.cols;
480 |
481 | p.drawRect(QRect(p1, p2));
482 | p.fillRect(QRect(p1, p2), color);
483 | }
484 | }
485 |
486 | void Image::detachAreasWindows()
487 | {
488 | areas = 0;
489 |
490 | clearOverlay();
491 | }
492 |
493 | void Image::detachDistancesWindows()
494 | {
495 | distances = 0;
496 |
497 | setSelectionMode();
498 |
499 | clearOverlay();
500 | }
501 |
502 | void Image::remapPoint(QPoint &p) const
503 | {
504 | int x = p.x();
505 | int y = p.y();
506 |
507 | int imageHeight = current.rows;
508 | int imageWidth = current.cols;
509 |
510 | int labelHeight = ui->imageLabel->height();
511 | int labelWidth = ui->imageLabel->width();
512 |
513 | if (ui->fitToScreenCheckBox->isChecked()) {
514 | int scaledImageWidth, scaledImageHeight;
515 |
516 | if (labelWidth * imageHeight > imageWidth * labelHeight) {
517 | scaledImageWidth = imageWidth * labelHeight / imageHeight;
518 | scaledImageHeight = labelHeight;
519 | } else {
520 | scaledImageWidth = labelWidth;
521 | scaledImageHeight = imageHeight * labelWidth / imageWidth;
522 | }
523 |
524 | x = (x - (labelWidth - scaledImageWidth) / 2) * imageWidth / scaledImageWidth;
525 | y = (y - (labelHeight - scaledImageHeight) / 2) * imageHeight / scaledImageHeight;
526 | } else if (imageWidth < labelWidth && imageHeight < labelHeight) {
527 | x -= (labelWidth - imageWidth) / 2;
528 | y -= (labelHeight - imageHeight) / 2;
529 | }
530 |
531 | if (x < 0)
532 | x = 0;
533 | else if (x >= imageWidth)
534 | x = imageWidth - 1;
535 |
536 | if (y < 0)
537 | y = 0;
538 | else if (y >= imageHeight)
539 | y = imageHeight - 1;
540 |
541 | p.setX(x);
542 | p.setY(y);
543 | }
544 |
545 | void Image::overlayAreas(std::vector const &stats)
546 | {
547 | if (areas == 0) {
548 | ui->withOverlayCheckBox->setChecked(true);
549 |
550 | areas = new TextListWindow("Areas",
551 | "N\tArea\tUnit",
552 | this);
553 |
554 | for (size_t i = 1; i < stats.size(); i++) {
555 | cv::ConnectedComponentStats stat = stats.at(i);
556 |
557 | areas->append(QString::number(i) + "\t" +
558 | QString::number(stat.area * scale * scale) + "\t" +
559 | unit + "^2");
560 |
561 | Text text;
562 | text.p = QPoint(stat.centroid_x, stat.centroid_y);
563 | text.s = QString::number(i);
564 |
565 | overlay.text.append(text);
566 |
567 | QPainter p(&overlayedPixmap);
568 | color.setAlpha(128);
569 | p.setPen(QPen(color));
570 | p.drawText((text.p * pixmap.width()) / current.cols,
571 | text.s);
572 | }
573 |
574 | connect(areas, SIGNAL(destroyed()),
575 | this, SLOT(detachAreasWindows()));
576 |
577 | ui->imageLabel->setPixmap(overlayedPixmap);
578 | }
579 | }
580 |
581 | void Image::on_withOverlayCheckBox_toggled(bool checked)
582 | {
583 | if (checked)
584 | ui->imageLabel->setPixmap(overlayedPixmap);
585 | else
586 | ui->imageLabel->setPixmap(pixmap);
587 | }
588 |
--------------------------------------------------------------------------------
/image.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Jorge Aparicio
3 | *
4 | * This file is part of ImageQ.
5 | *
6 | * ImageQ is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 |
11 | * ImageQ is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 |
16 | * You should have received a copy of the GNU General Public License
17 | * along with ImageQ. If not, see .
18 | */
19 |
20 | #pragma once
21 |
22 | #include
23 | #include
24 |
25 | #include
26 |
27 | #include
28 |
29 | class TextListWindow;
30 |
31 | namespace Ui {
32 | class Image;
33 | }
34 |
35 | struct Text {
36 | QPoint p;
37 | QString s;
38 | };
39 |
40 | class Image : public QWidget
41 | {
42 | Q_OBJECT
43 |
44 | public:
45 | enum SelectionMode {
46 | None, Line, Rectangle, Distance
47 | };
48 |
49 | explicit Image(QString pathToImage, QWidget *parent = 0);
50 | explicit Image(cv::Mat const& image, QWidget *parent = 0);
51 | ~Image();
52 |
53 | cv::Mat current;
54 | cv::Mat previous;
55 | float scale;
56 | QString unit;
57 | TextListWindow *areas;
58 | TextListWindow *distances;
59 |
60 | void backup();
61 | void HSV(std::vector& hsv) const;
62 | void revert();
63 | void RGB(std::vector& rgb) const;
64 | void undo();
65 |
66 | signals:
67 | void exitSelectionMode();
68 | void lineSelected(QLine const& line, QPoint center = QPoint());
69 | void rectangleSelected(QRect const& rect);
70 | void status(QString const& msg);
71 |
72 | public slots:
73 | void display();
74 | void pixelInfo(QPoint p) const;
75 | void mouseDoubleClick(QPoint p);
76 | void mouseMove(QPoint p);
77 | void mousePress(QPoint p);
78 | void mouseRelease(QPoint p);
79 | void on_fitToScreenCheckBox_toggled(bool checked);
80 | void rescale();
81 | void setSelectionMode(SelectionMode mode = None);
82 | void update();
83 |
84 | void clearOverlay();
85 | void loadOverlay();
86 | void detachAreasWindows();
87 | void detachDistancesWindows();
88 | void overlayAreas(std::vector const &stats);
89 |
90 | private slots:
91 | void on_withOverlayCheckBox_toggled(bool checked);
92 |
93 | private:
94 | Ui::Image *ui;
95 | cv::Mat first;
96 | QPixmap pixmap, tempPixmap, overlayedPixmap;
97 | QPoint p1, p2;
98 | QRect rect;
99 | QColor color;
100 | bool mousePressed;
101 | SelectionMode selectionMode;
102 | struct {
103 | QVector line;
104 | QVector text;
105 | QVector rect;
106 | } overlay;
107 |
108 | void remapPoint(QPoint &p) const;
109 | void initialize();
110 | };
111 |
--------------------------------------------------------------------------------
/image.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Image
4 |
5 |
6 |
7 | 0
8 | 0
9 | 747
10 | 154
11 |
12 |
13 |
14 | Form
15 |
16 |
17 | -
18 |
19 |
-
20 |
21 |
22 | Fit to screen
23 |
24 |
25 | true
26 |
27 |
28 |
29 | -
30 |
31 |
32 | With overlay
33 |
34 |
35 |
36 | -
37 |
38 |
39 | Qt::Horizontal
40 |
41 |
42 |
43 | 40
44 | 20
45 |
46 |
47 |
48 |
49 | -
50 |
51 |
52 | Width
53 |
54 |
55 |
56 | -
57 |
58 |
59 | -
60 |
61 |
62 |
63 | -
64 |
65 |
66 | Height:
67 |
68 |
69 |
70 | -
71 |
72 |
73 | -
74 |
75 |
76 |
77 | -
78 |
79 |
80 | Depth:
81 |
82 |
83 |
84 | -
85 |
86 |
87 | -
88 |
89 |
90 |
91 | -
92 |
93 |
94 | Channels:
95 |
96 |
97 |
98 | -
99 |
100 |
101 | -
102 |
103 |
104 |
105 | -
106 |
107 |
108 | Minimum:
109 |
110 |
111 |
112 | -
113 |
114 |
115 | -
116 |
117 |
118 |
119 | -
120 |
121 |
122 | Maximum:
123 |
124 |
125 |
126 | -
127 |
128 |
129 | -
130 |
131 |
132 |
133 |
134 |
135 | -
136 |
137 |
138 | true
139 |
140 |
141 |
142 |
143 | 0
144 | 0
145 | 727
146 | 76
147 |
148 |
149 |
150 |
-
151 |
152 |
153 | Image goes here.
154 |
155 |
156 | Qt::AlignCenter
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 | -
165 |
166 |
-
167 |
168 |
169 | Qt::Horizontal
170 |
171 |
172 |
173 | 40
174 | 20
175 |
176 |
177 |
178 |
179 | -
180 |
181 |
182 | X:
183 |
184 |
185 |
186 | -
187 |
188 |
189 | -
190 |
191 |
192 |
193 | -
194 |
195 |
196 | Y:
197 |
198 |
199 |
200 | -
201 |
202 |
203 | -
204 |
205 |
206 |
207 | -
208 |
209 |
210 | Value:
211 |
212 |
213 |
214 | -
215 |
216 |
217 | -
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 | ImageLabel
228 | QLabel
229 |
230 |
231 |
232 |
233 |
234 |
235 |
--------------------------------------------------------------------------------
/imagelabel.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Jorge Aparicio
3 | *
4 | * This file is part of ImageQ.
5 | *
6 | * ImageQ is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 |
11 | * ImageQ is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 |
16 | * You should have received a copy of the GNU General Public License
17 | * along with ImageQ. If not, see .
18 | */
19 |
20 | #include "imagelabel.h"
21 |
22 | #include
23 |
24 | ImageLabel::ImageLabel(QWidget *parent) :
25 | QLabel(parent)
26 | {
27 | this->setMouseTracking(true);
28 | }
29 |
30 | void ImageLabel::mouseDoubleClickEvent(QMouseEvent *ev)
31 | {
32 | emit mouseDoubleClick(ev->pos());
33 | }
34 |
35 | void ImageLabel::mouseMoveEvent(QMouseEvent *ev)
36 | {
37 | emit mouseHover(ev->pos());
38 | }
39 |
40 | void ImageLabel::mousePressEvent(QMouseEvent *ev)
41 | {
42 | emit mousePress(ev->pos());
43 | }
44 |
45 | void ImageLabel::mouseReleaseEvent(QMouseEvent *ev)
46 | {
47 | emit mouseRelease(ev->pos());
48 | }
49 |
50 | void ImageLabel::resizeEvent(QResizeEvent *)
51 | {
52 | emit resized();
53 | }
54 |
--------------------------------------------------------------------------------
/imagelabel.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Jorge Aparicio
3 | *
4 | * This file is part of ImageQ.
5 | *
6 | * ImageQ is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 |
11 | * ImageQ is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 |
16 | * You should have received a copy of the GNU General Public License
17 | * along with ImageQ. If not, see .
18 | */
19 |
20 | #pragma once
21 |
22 | #include
23 |
24 | class ImageLabel : public QLabel
25 | {
26 | Q_OBJECT
27 | public:
28 | explicit ImageLabel(QWidget *parent = 0);
29 |
30 | protected:
31 | void mouseDoubleClickEvent(QMouseEvent *ev);
32 | void mouseMoveEvent(QMouseEvent *ev);
33 | void mousePressEvent(QMouseEvent *ev);
34 | void mouseReleaseEvent(QMouseEvent *ev);
35 | void resizeEvent(QResizeEvent *);
36 |
37 | signals:
38 | void mouseDoubleClick(QPoint p);
39 | void mouseHover(QPoint p);
40 | void mousePress(QPoint p);
41 | void mouseRelease(QPoint p);
42 | void resized();
43 |
44 | public slots:
45 |
46 | };
47 |
--------------------------------------------------------------------------------
/main.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Jorge Aparicio
3 | *
4 | * This file is part of ImageQ.
5 | *
6 | * ImageQ is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 |
11 | * ImageQ is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 |
16 | * You should have received a copy of the GNU General Public License
17 | * along with ImageQ. If not, see .
18 | */
19 |
20 | #include
21 | #include "mainwindow.h"
22 |
23 | int main(int argc, char *argv[])
24 | {
25 | QApplication a(argc, argv);
26 | MainWindow w;
27 | w.show();
28 |
29 | return a.exec();
30 | }
31 |
--------------------------------------------------------------------------------
/mainwindow.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Jorge Aparicio
3 | *
4 | * This file is part of ImageQ.
5 | *
6 | * ImageQ is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 |
11 | * ImageQ is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 |
16 | * You should have received a copy of the GNU General Public License
17 | * along with ImageQ. If not, see .
18 | */
19 |
20 | #include "mainwindow.h"
21 | #include "ui_mainwindow.h"
22 |
23 | #include
24 |
25 | #include "image.h"
26 |
27 | #include
28 | #include
29 |
30 | #include
31 |
32 | #include "aboutwindow.h"
33 | #include "blurwindow.h"
34 | #include "cannywindow.h"
35 | #include "gradientwindow.h"
36 | #include "histogramwindow.h"
37 | #include "morphologywindow.h"
38 | #include "thresholdwindow.h"
39 | #include "setscalewindow.h"
40 |
41 | // TODO: Batch processing
42 | // TODO: Channels merge
43 | // TODO: Macroing
44 | // TODO: Video processing...?
45 | // TODO: Watershed
46 |
47 | MainWindow::MainWindow(QWidget *parent) :
48 | QMainWindow(parent),
49 | ui(new Ui::MainWindow),
50 | workingImage(0),
51 | aboutWindow(0),
52 | cannyWindow(0),
53 | gradientWindow(0),
54 | histogramWindow(0),
55 | morphologyWindow(0),
56 | thresholdWindow(0)
57 | {
58 | ui->setupUi(this);
59 |
60 | ui->mainToolBar->hide();
61 |
62 | this->showMaximized();
63 | }
64 |
65 | MainWindow::~MainWindow()
66 | {
67 | delete ui;
68 | }
69 |
70 | void MainWindow::on_actionAbout_triggered()
71 | {
72 | aboutWindow = new AboutWindow(this);
73 | }
74 |
75 | void MainWindow::on_actionBlur_triggered()
76 | {
77 | if (workingImage) {
78 | if (workingImage->current.channels() == 1) {
79 | disableOtherTabs();
80 | setOperationsEnabled(false);
81 |
82 | blurWindow = new BlurWindow(workingImage, this);
83 |
84 | connect(blurWindow, SIGNAL(destroyed()),
85 | this, SLOT(enableAllTabs()));
86 |
87 | connect(blurWindow, SIGNAL(destroyed()),
88 | this, SLOT(enableAllOperations()));
89 | }
90 | }
91 | }
92 |
93 | void MainWindow::on_actionCanny_triggered()
94 | {
95 | if (workingImage) {
96 | if (workingImage->current.channels() == 1) {
97 | disableOtherTabs();
98 | setOperationsEnabled(false);
99 |
100 | cannyWindow = new CannyWindow(workingImage, this);
101 |
102 | connect(cannyWindow, SIGNAL(destroyed()),
103 | this, SLOT(enableAllTabs()));
104 |
105 | connect(cannyWindow, SIGNAL(destroyed()),
106 | this, SLOT(enableAllOperations()));
107 | }
108 | }
109 | }
110 |
111 | void MainWindow::on_actionCrop_triggered()
112 | {
113 | if (workingImage) {
114 | disableOtherTabs();
115 | setOperationsEnabled(false);
116 |
117 | connect(workingImage, SIGNAL(rectangleSelected(QRect)),
118 | this, SLOT(crop(QRect)));
119 |
120 | connect(workingImage, SIGNAL(status(QString)),
121 | ui->statusBar, SLOT(showMessage(QString)));
122 |
123 | workingImage->setSelectionMode(Image::Rectangle);
124 | }
125 | }
126 |
127 | void MainWindow::on_actionClear_triggered()
128 | {
129 | workingImage->clearOverlay();
130 | workingImage->detachDistancesWindows();
131 | }
132 |
133 |
134 | void MainWindow::on_actionClose_triggered()
135 | {
136 | this->close();
137 | }
138 |
139 | void MainWindow::on_actionDistance_triggered()
140 | {
141 | if (workingImage) {
142 | if (workingImage->distances == 0) {
143 | disableOtherTabs();
144 | setOperationsEnabled(false);
145 |
146 | workingImage->clearOverlay();
147 |
148 | connect(workingImage, SIGNAL(status(QString)),
149 | ui->statusBar, SLOT(showMessage(QString)));
150 |
151 | connect(workingImage, SIGNAL(exitSelectionMode()),
152 | this, SLOT(finishMeasuring()));
153 |
154 | workingImage->setSelectionMode(Image::Distance);
155 | }
156 | }
157 | }
158 |
159 | void MainWindow::on_actionEqualize_triggered()
160 | {
161 | if (workingImage) {
162 | if (workingImage->current.channels() == 1) {
163 | workingImage->backup();
164 |
165 | cv::equalizeHist(workingImage->previous, workingImage->current);
166 |
167 | workingImage->update();
168 | }
169 | }
170 | }
171 |
172 | void MainWindow::on_actionGradient_triggered()
173 | {
174 | if (workingImage) {
175 | if (workingImage->current.channels() == 1) {
176 | disableOtherTabs();
177 | setOperationsEnabled(false);
178 |
179 | gradientWindow = new GradientWindow(workingImage, this);
180 |
181 | connect(gradientWindow, SIGNAL(destroyed()),
182 | this, SLOT(enableAllTabs()));
183 |
184 | connect(gradientWindow, SIGNAL(destroyed()),
185 | this, SLOT(enableAllOperations()));
186 | }
187 | }
188 | }
189 |
190 | void MainWindow::on_actionGrayscale_triggered()
191 | {
192 | if (workingImage) {
193 | if (workingImage->current.channels() == 3) {
194 | int index = ui->imagesTabWidget->currentIndex();
195 | QString name = ui->imagesTabWidget->tabText(index);
196 | cv::Mat grayscale;
197 |
198 | cv::cvtColor(workingImage->current, grayscale, CV_BGR2GRAY);
199 |
200 | Image* newImage = new Image(grayscale, this);
201 |
202 | images.push_back(newImage);
203 |
204 | ui->imagesTabWidget->insertTab(++index,
205 | newImage,
206 | name + " (gray)");
207 | }
208 | }
209 | }
210 |
211 | void MainWindow::on_actionHistogram_triggered()
212 | {
213 | if (workingImage) {
214 | if (workingImage->current.channels() == 1) {
215 | disableOtherTabs();
216 | setOperationsEnabled(false);
217 |
218 | histogramWindow = new HistogramWindow(workingImage->current, this);
219 |
220 | connect(histogramWindow, SIGNAL(destroyed()),
221 | this, SLOT(enableAllTabs()));
222 |
223 | connect(histogramWindow, SIGNAL(destroyed()),
224 | this, SLOT(enableAllOperations()));
225 | }
226 | }
227 | }
228 |
229 | void MainWindow::on_actionHSV_triggered()
230 | {
231 | if (workingImage) {
232 | if (workingImage->current.channels() == 3) {
233 | int index = ui->imagesTabWidget->currentIndex();
234 | QString name = ui->imagesTabWidget->tabText(index);
235 | std::vector hsv;
236 |
237 | workingImage->HSV(hsv);
238 |
239 | for (int i = 0; i < 3; i++) {
240 | QString newName;
241 | Image* newImage = new Image(hsv.at(i), this);
242 | images.push_back(newImage);
243 |
244 | switch (i) {
245 | case 0:
246 | newName = name + " (H)";
247 | break;
248 | case 1:
249 | newName = name + " (S)";
250 | break;
251 | case 2:
252 | newName = name + " (V)";
253 | break;
254 | }
255 |
256 | ui->imagesTabWidget->insertTab(++index, newImage, newName);
257 | }
258 | }
259 | }
260 | }
261 |
262 | void MainWindow::on_actionInvert_triggered()
263 | {
264 | if (workingImage) {
265 | std::vector channels;
266 |
267 | workingImage->backup();
268 |
269 | cv::split(workingImage->current, channels);
270 |
271 | for (size_t i = 0; i < channels.size(); i++)
272 | channels.at(i) = 255 - channels.at(i);
273 |
274 | cv::merge(channels, workingImage->current);
275 |
276 | workingImage->update();
277 | }
278 | }
279 |
280 | void MainWindow::on_actionMorphology_triggered()
281 | {
282 | if (workingImage) {
283 | if (workingImage->current.channels() == 1) {
284 | disableOtherTabs();
285 | setOperationsEnabled(false);
286 |
287 | morphologyWindow = new MorphologyWindow(workingImage, this);
288 |
289 | connect(morphologyWindow, SIGNAL(destroyed()),
290 | this, SLOT(enableAllTabs()));
291 |
292 | connect(morphologyWindow, SIGNAL(destroyed()),
293 | this, SLOT(enableAllOperations()));
294 | }
295 | }
296 | }
297 |
298 | void MainWindow::on_actionOpen_triggered()
299 | {
300 | setOperationsEnabled(false);
301 |
302 | QString filename =
303 | QFileDialog::getOpenFileName(this, "Open", QString(),
304 | "Image Files (*.png *.jpg *.bmp *.tif)");
305 |
306 | setOperationsEnabled(true);
307 |
308 | if (!filename.isEmpty()) {
309 | images.push_back(new Image(filename, this));
310 |
311 | #ifdef Q_OS_WIN32
312 | int index = filename.lastIndexOf("\\");
313 | #else
314 | int index = filename.lastIndexOf("/");
315 | #endif
316 |
317 | if (index != -1)
318 | filename = filename.right(filename.length() - 1 - index);
319 |
320 | ui->imagesTabWidget->addTab(images.last(), filename);
321 | }
322 | }
323 |
324 | void MainWindow::on_actionParticles_triggered()
325 | {
326 | if (workingImage) {
327 | if (workingImage->current.channels() == 1 && workingImage->areas == 0) {
328 | workingImage->clearOverlay();
329 |
330 | cv::Mat labels(workingImage->current.rows,
331 | workingImage->current.cols,
332 | CV_32S);
333 | std::vector stats;
334 |
335 | cv::connectedComponentsWithStats(labels,
336 | workingImage->current,
337 | stats);
338 |
339 | workingImage->overlayAreas(stats);
340 | }
341 | }
342 | }
343 |
344 | void MainWindow::on_actionRevert_triggered()
345 | {
346 | if (workingImage)
347 | workingImage->revert();
348 | }
349 |
350 | void MainWindow::on_actionRGB_triggered()
351 | {
352 | if (workingImage) {
353 | if (workingImage->current.channels() == 3) {
354 | int index = ui->imagesTabWidget->currentIndex();
355 | QString name = ui->imagesTabWidget->tabText(index);
356 | std::vector rgb;
357 |
358 | workingImage->RGB(rgb);
359 |
360 | for (int i = 0; i < 3; i++) {
361 | QString newName;
362 | Image* newImage = new Image(rgb.at(i), this);
363 | images.push_back(newImage);
364 |
365 | switch (i) {
366 | case 0:
367 | newName = name + " (R)";
368 | break;
369 | case 1:
370 | newName = name + " (G)";
371 | break;
372 | case 2:
373 | newName = name + " (B)";
374 | break;
375 | }
376 |
377 | ui->imagesTabWidget->insertTab(++index, newImage, newName);
378 | }
379 | }
380 | }
381 | }
382 |
383 | void MainWindow::on_actionSave_triggered()
384 | {
385 | if (workingImage) {
386 | setOperationsEnabled(false);
387 |
388 | QString filename = QFileDialog::getSaveFileName(this, QLatin1String("Save"));
389 |
390 | setOperationsEnabled(true);
391 |
392 | if (!filename.isEmpty()) {
393 | std::vector qualityType;
394 |
395 | qualityType.push_back(CV_IMWRITE_JPEG_QUALITY);
396 | qualityType.push_back(90);
397 |
398 | filename += ".jpg";
399 |
400 | cv::imwrite(filename.toStdString(), workingImage->current, qualityType);
401 | }
402 | }
403 | }
404 |
405 | void MainWindow::on_actionSet_Scale_triggered()
406 | {
407 | if (workingImage) {
408 | disableOtherTabs();
409 | setOperationsEnabled(false);
410 |
411 | setScaleWindow = new SetScaleWindow(workingImage, this);
412 |
413 | connect(workingImage, SIGNAL(status(QString)),
414 | ui->statusBar, SLOT(showMessage(QString)));
415 |
416 | connect(setScaleWindow, SIGNAL(destroyed()),
417 | this, SLOT(releaseStatusBar()));
418 |
419 | connect(setScaleWindow, SIGNAL(destroyed()),
420 | this, SLOT(enableAllTabs()));
421 |
422 | connect(setScaleWindow, SIGNAL(destroyed()),
423 | this, SLOT(enableAllOperations()));
424 | }
425 | }
426 |
427 | void MainWindow::on_actionStretch_triggered()
428 | {
429 | if (workingImage) {
430 | workingImage->backup();
431 |
432 | cv::normalize(workingImage->previous,
433 | workingImage->current,
434 | 0,
435 | 255,
436 | cv::NORM_MINMAX);
437 |
438 | workingImage->update();
439 | }
440 | }
441 |
442 | void MainWindow::on_actionThreshold_triggered()
443 | {
444 | if (workingImage) {
445 | if (workingImage->current.channels() == 1) {
446 | disableOtherTabs();
447 | setOperationsEnabled(false);
448 |
449 | thresholdWindow = new ThresholdWindow(workingImage, this);
450 |
451 | connect(thresholdWindow, SIGNAL(destroyed()),
452 | this, SLOT(enableAllTabs()));
453 |
454 | connect(thresholdWindow, SIGNAL(destroyed()),
455 | this, SLOT(enableAllOperations()));
456 | }
457 | }
458 | }
459 |
460 | void MainWindow::on_actionUndo_triggered()
461 | {
462 | if (workingImage)
463 | workingImage->undo();
464 | }
465 |
466 | void MainWindow::on_imagesTabWidget_currentChanged(QWidget *image)
467 | {
468 | if (workingImage)
469 | workingImage->clearOverlay();
470 |
471 | workingImage = (Image*)image;
472 |
473 | if (workingImage != 0)
474 | workingImage->update();
475 | }
476 |
477 | void MainWindow::on_imagesTabWidget_tabCloseRequested(int index)
478 | {
479 | index = images.indexOf((Image*)(ui->imagesTabWidget->widget(index)));
480 |
481 | delete images.at(index);
482 | images.remove(index);
483 | }
484 |
485 | void MainWindow::crop(QRect rect)
486 | {
487 | int index = ui->imagesTabWidget->currentIndex();
488 | QString name = ui->imagesTabWidget->tabText(index);
489 |
490 | if (rect.width() != 0 && rect.height() != 0) {
491 | cv::Rect roi(rect.x(), rect.y(), rect.width(), rect.height());
492 | cv::Mat mat = workingImage->current(roi);
493 |
494 | Image* newImage = new Image(mat, this);
495 | images.push_back(newImage);
496 |
497 | ui->imagesTabWidget->insertTab(++index, newImage, name + " (crop)");
498 | }
499 |
500 | enableAllTabs();
501 | enableAllOperations();
502 |
503 | disconnect(workingImage, SIGNAL(rectangleSelected(QRect)),
504 | this, SLOT(crop(QRect)));
505 |
506 | disconnect(workingImage, SIGNAL(status(QString)),
507 | ui->statusBar, SLOT(showMessage(QString)));
508 |
509 | ui->statusBar->clearMessage();
510 | }
511 |
512 | void MainWindow::disableOtherTabs()
513 | {
514 | if (workingImage) {
515 | int index = ui->imagesTabWidget->currentIndex();
516 |
517 | ui->imagesTabWidget->setTabsClosable(false);
518 |
519 | for (int i = 0; i < ui->imagesTabWidget->count(); i++)
520 | if (i != index)
521 | ui->imagesTabWidget->setTabEnabled(i, false);
522 | }
523 | }
524 |
525 | void MainWindow::enableAllOperations()
526 | {
527 | setOperationsEnabled(true);
528 | }
529 |
530 | void MainWindow::enableAllTabs()
531 | {
532 | ui->imagesTabWidget->setTabsClosable(true);
533 |
534 | for (int i = 0; i < ui->imagesTabWidget->count(); i++)
535 | ui->imagesTabWidget->setTabEnabled(i, true);
536 | }
537 |
538 | void MainWindow::finishMeasuring()
539 | {
540 | enableAllTabs();
541 | enableAllOperations();
542 |
543 | ui->statusBar->clearMessage();
544 |
545 | disconnect(workingImage, SIGNAL(status(QString)),
546 | ui->statusBar, SLOT(showMessage(QString)));
547 |
548 | disconnect(workingImage, SIGNAL(exitSelectionMode()),
549 | this, SLOT(finishMeasuring()));
550 | }
551 |
552 | void MainWindow::releaseStatusBar()
553 | {
554 | disconnect(workingImage, SIGNAL(status(QString)),
555 | ui->statusBar, SLOT(showMessage(QString)));
556 | }
557 |
558 | void MainWindow::setOperationsEnabled(bool enable)
559 | {
560 | ui->actionBlur->setEnabled(enable);
561 | ui->actionCanny->setEnabled(enable);
562 | ui->actionCrop->setEnabled(enable);
563 | ui->actionDistance->setEnabled(enable);
564 | ui->actionEqualize->setEnabled(enable);
565 | ui->actionGradient->setEnabled(enable);
566 | ui->actionGrayscale->setEnabled(enable);
567 | ui->actionHistogram->setEnabled(enable);
568 | ui->actionHSV->setEnabled(enable);
569 | ui->actionInvert->setEnabled(enable);
570 | ui->actionMorphology->setEnabled(enable);
571 | ui->actionOpen->setEnabled(enable);
572 | ui->actionParticles->setEnabled(enable);
573 | ui->actionRevert->setEnabled(enable);
574 | ui->actionRGB->setEnabled(enable);
575 | ui->actionSave->setEnabled(enable);
576 | ui->actionSet_Scale->setEnabled(enable);
577 | ui->actionStretch->setEnabled(enable);
578 | ui->actionThreshold->setEnabled(enable);
579 | ui->actionUndo->setEnabled(enable);
580 | ui->actionClear->setEnabled(enable);
581 | }
582 |
--------------------------------------------------------------------------------
/mainwindow.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Jorge Aparicio
3 | *
4 | * This file is part of ImageQ.
5 | *
6 | * ImageQ is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 |
11 | * ImageQ is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 |
16 | * You should have received a copy of the GNU General Public License
17 | * along with ImageQ. If not, see .
18 | */
19 |
20 | #pragma once
21 |
22 | #include
23 |
24 | class Image;
25 |
26 | class AboutWindow;
27 | class BlurWindow;
28 | class CannyWindow;
29 | class GradientWindow;
30 | class HistogramWindow;
31 | class MorphologyWindow;
32 | class ThresholdWindow;
33 | class SetScaleWindow;
34 |
35 | namespace Ui {
36 | class MainWindow;
37 | }
38 |
39 | class MainWindow : public QMainWindow
40 | {
41 | Q_OBJECT
42 |
43 | public:
44 | explicit MainWindow(QWidget *parent = 0);
45 | ~MainWindow();
46 |
47 | private slots:
48 | void on_actionAbout_triggered();
49 | void on_actionBlur_triggered();
50 | void on_actionCanny_triggered();
51 | void on_actionCrop_triggered();
52 | void on_actionClear_triggered();
53 | void on_actionClose_triggered();
54 | void on_actionDistance_triggered();
55 | void on_actionEqualize_triggered();
56 | void on_actionGradient_triggered();
57 | void on_actionGrayscale_triggered();
58 | void on_actionHistogram_triggered();
59 | void on_actionHSV_triggered();
60 | void on_actionInvert_triggered();
61 | void on_actionMorphology_triggered();
62 | void on_actionOpen_triggered();
63 | void on_actionParticles_triggered();
64 | void on_actionRevert_triggered();
65 | void on_actionRGB_triggered();
66 | void on_actionSave_triggered();
67 | void on_actionSet_Scale_triggered();
68 | void on_actionStretch_triggered();
69 | void on_actionThreshold_triggered();
70 | void on_actionUndo_triggered();
71 |
72 | void on_imagesTabWidget_currentChanged(QWidget *image);
73 | void on_imagesTabWidget_tabCloseRequested(int index);
74 |
75 | void crop(QRect rect);
76 | void disableOtherTabs();
77 | void enableAllOperations();
78 | void enableAllTabs();
79 | void finishMeasuring();
80 | void releaseStatusBar();
81 |
82 | private:
83 | Ui::MainWindow *ui;
84 | QVector images;
85 | Image* workingImage;
86 | AboutWindow *aboutWindow;
87 | BlurWindow *blurWindow;
88 | CannyWindow *cannyWindow;
89 | GradientWindow *gradientWindow;
90 | HistogramWindow *histogramWindow;
91 | MorphologyWindow *morphologyWindow;
92 | ThresholdWindow *thresholdWindow;
93 | SetScaleWindow *setScaleWindow;
94 |
95 | void setOperationsEnabled(bool enable);
96 | };
97 |
--------------------------------------------------------------------------------
/mainwindow.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | MainWindow
4 |
5 |
6 |
7 | 0
8 | 0
9 | 709
10 | 186
11 |
12 |
13 |
14 | ImageQ
15 |
16 |
17 |
18 | -
19 |
20 |
21 | -1
22 |
23 |
24 | true
25 |
26 |
27 | true
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 | TopToolBarArea
36 |
37 |
38 | false
39 |
40 |
41 |
42 |
147 |
148 |
149 | Equalize
150 |
151 |
152 |
153 |
154 | Invert
155 |
156 |
157 |
158 |
159 | Threshold
160 |
161 |
162 |
163 |
164 | Histogram
165 |
166 |
167 |
168 |
169 | Gradient
170 |
171 |
172 |
173 |
174 | About
175 |
176 |
177 |
178 |
179 | Stretch
180 |
181 |
182 |
183 |
184 | Canny
185 |
186 |
187 |
188 |
189 | Undo
190 |
191 |
192 |
193 |
194 | Open
195 |
196 |
197 |
198 |
199 | Save
200 |
201 |
202 |
203 |
204 | Close
205 |
206 |
207 |
208 |
209 | Revert
210 |
211 |
212 |
213 |
214 | Blur
215 |
216 |
217 |
218 |
219 | Morphology
220 |
221 |
222 |
223 |
224 | RGB
225 |
226 |
227 |
228 |
229 | HSV
230 |
231 |
232 |
233 |
234 | Grayscale
235 |
236 |
237 |
238 |
239 | Crop
240 |
241 |
242 |
243 |
244 | Set Scale
245 |
246 |
247 |
248 |
249 | Distance
250 |
251 |
252 |
253 |
254 | Particles
255 |
256 |
257 |
258 |
259 | Clear
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
--------------------------------------------------------------------------------
/mat2qimage.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Jorge Aparicio
3 | *
4 | * This file is part of ImageQ.
5 | *
6 | * ImageQ is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 |
11 | * ImageQ is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 |
16 | * You should have received a copy of the GNU General Public License
17 | * along with ImageQ. If not, see .
18 | */
19 |
20 | #include "mat2qimage.h"
21 |
22 | #include
23 |
24 | QImage Mat2QImage(cv::Mat const& src)
25 | {
26 | QImage dest(src.cols, src.rows, QImage::Format_ARGB32);
27 |
28 | const float scale = 255.0;
29 |
30 | if (src.depth() == CV_8U) {
31 | if (src.channels() == 1) {
32 | for (int i = 0; i < src.rows; ++i) {
33 | for (int j = 0; j < src.cols; ++j) {
34 | int level = src.at(i, j);
35 | dest.setPixel(j, i, qRgb(level, level, level));
36 | }
37 | }
38 | } else if (src.channels() == 3) {
39 | for (int i = 0; i < src.rows; ++i) {
40 | for (int j = 0; j < src.cols; ++j) {
41 | cv::Vec3b bgr = src.at(i, j);
42 | dest.setPixel(j, i, qRgb(bgr[2], bgr[1], bgr[0]));
43 | }
44 | }
45 | }
46 | } else if (src.depth() == CV_32F) {
47 | if (src.channels() == 1) {
48 | for (int i = 0; i < src.rows; ++i) {
49 | for (int j = 0; j < src.cols; ++j) {
50 | int level = scale * src.at(i, j);
51 | dest.setPixel(j, i, qRgb(level, level, level));
52 | }
53 | }
54 | } else if (src.channels() == 3) {
55 | for (int i = 0; i < src.rows; ++i) {
56 | for (int j = 0; j < src.cols; ++j) {
57 | cv::Vec3f bgr = scale * src.at(i, j);
58 | dest.setPixel(j, i, qRgb(bgr[2], bgr[1], bgr[0]));
59 | }
60 | }
61 | }
62 | }
63 |
64 | return dest;
65 | }
66 |
--------------------------------------------------------------------------------
/mat2qimage.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Jorge Aparicio
3 | *
4 | * This file is part of ImageQ.
5 | *
6 | * ImageQ is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 |
11 | * ImageQ is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 |
16 | * You should have received a copy of the GNU General Public License
17 | * along with ImageQ. If not, see .
18 | */
19 |
20 | #pragma once
21 |
22 | #include
23 |
24 | namespace cv {
25 | class Mat;
26 | }
27 |
28 | QImage Mat2QImage(cv::Mat const&);
29 |
--------------------------------------------------------------------------------
/morphologywindow.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Jorge Aparicio
3 | *
4 | * This file is part of ImageQ.
5 | *
6 | * ImageQ is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 |
11 | * ImageQ is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 |
16 | * You should have received a copy of the GNU General Public License
17 | * along with ImageQ. If not, see .
18 | */
19 |
20 | #include "morphologywindow.h"
21 | #include "ui_morphologywindow.h"
22 |
23 | #include "mat2qimage.h"
24 | #include "image.h"
25 |
26 | #include
27 |
28 | MorphologyWindow::MorphologyWindow(Image* image,
29 | QWidget *parent) :
30 | QMainWindow(parent),
31 | ui(new Ui::MorphologyWindow),
32 | image(image),
33 | abort(true)
34 | {
35 | ui->setupUi(this);
36 |
37 | image->backup();
38 |
39 | connect(this, SIGNAL(update()),
40 | image, SLOT(update()));
41 |
42 | this->setAttribute(Qt::WA_DeleteOnClose);
43 | this->setFixedSize(this->size());
44 |
45 | this->show();
46 |
47 | updateStructuringElement();
48 | morphology();
49 | }
50 |
51 | MorphologyWindow::~MorphologyWindow()
52 | {
53 | delete ui;
54 | }
55 |
56 | void MorphologyWindow::closeEvent(QCloseEvent *)
57 | {
58 | if (abort)
59 | image->undo();
60 | }
61 |
62 | void MorphologyWindow::on_cancelPushButton_clicked()
63 | {
64 | this->close();
65 | }
66 |
67 | void MorphologyWindow::on_okPushButton_clicked()
68 | {
69 | abort = false;
70 |
71 | this->close();
72 | }
73 |
74 | void MorphologyWindow::on_closeRadioButton_toggled(bool checked)
75 | {
76 | ui->iterationsSpinBox->setDisabled(checked);
77 |
78 | if (checked) {
79 | ui->iterationsSpinBox->setValue(1);
80 |
81 | morphology();
82 | }
83 | }
84 |
85 | void MorphologyWindow::on_crossRadioButton_toggled(bool checked)
86 | {
87 | if (checked) {
88 | updateStructuringElement();
89 |
90 | morphology();
91 | }
92 | }
93 |
94 | void MorphologyWindow::on_customRadioButton_toggled(bool checked)
95 | {
96 | if (checked) {
97 | updateStructuringElement();
98 |
99 | morphology();
100 | }
101 | }
102 |
103 | void MorphologyWindow::on_dilateRadioButton_toggled(bool checked)
104 | {
105 | ui->iterationsSpinBox->setEnabled(checked);
106 |
107 | if (checked)
108 | morphology();
109 | }
110 |
111 | void MorphologyWindow::on_diskRadioButton_toggled(bool checked)
112 | {
113 | if (checked) {
114 | updateStructuringElement();
115 |
116 | morphology();
117 | }
118 | }
119 |
120 | void MorphologyWindow::on_erodeRadioButton_toggled(bool checked)
121 | {
122 | ui->iterationsSpinBox->setEnabled(checked);
123 |
124 | if (checked)
125 | morphology();
126 | }
127 |
128 | void MorphologyWindow::on_openRadioButton_toggled(bool checked)
129 | {
130 | ui->iterationsSpinBox->setDisabled(checked);
131 |
132 | if (checked) {
133 | ui->iterationsSpinBox->setValue(1);
134 |
135 | morphology();
136 | }
137 | }
138 |
139 | void MorphologyWindow::on_squareRadioButton_toggled(bool checked)
140 | {
141 | if (checked) {
142 | updateStructuringElement();
143 |
144 | morphology();
145 | }
146 | }
147 |
148 | void MorphologyWindow::on_xRadioButton_toggled(bool checked)
149 | {
150 | if (checked) {
151 | updateStructuringElement();
152 |
153 | morphology();
154 | }
155 | }
156 |
157 | void MorphologyWindow::on_iterationsSpinBox_valueChanged(int)
158 | {
159 | morphology();
160 | }
161 |
162 | void MorphologyWindow::on_sizeSpinBox_valueChanged(int)
163 | {
164 | updateStructuringElement();
165 |
166 | morphology();
167 | }
168 |
169 | void MorphologyWindow::morphology()
170 | {
171 | int iterations = ui->iterationsSpinBox->value();
172 |
173 | if (ui->closeRadioButton->isChecked()) {
174 | cv::dilate(image->previous, image->current, structuringElement);
175 | cv::erode(image->current, image->current, structuringElement);
176 | } else if (ui->dilateRadioButton->isChecked()) {
177 | cv::dilate(image->previous,
178 | image->current,
179 | structuringElement,
180 | cv::Point(-1, -1),
181 | iterations);
182 | } else if (ui->erodeRadioButton->isChecked()) {
183 | cv::erode(image->previous,
184 | image->current,
185 | structuringElement,
186 | cv::Point(-1, -1),
187 | iterations);
188 | } else if (ui->openRadioButton->isChecked()) {
189 | cv::erode(image->previous, image->current, structuringElement);
190 | cv::dilate(image->current, image->current, structuringElement);
191 | }
192 |
193 | emit update();
194 | }
195 |
196 | void MorphologyWindow::updateStructuringElement()
197 | {
198 | int size = ui->sizeSpinBox->value();
199 |
200 | if (ui->squareRadioButton->isChecked()) {
201 | structuringElement = cv::Mat::ones(size, size, CV_8U) * 255;
202 | } else {
203 | structuringElement = cv::Mat::zeros(size, size, CV_8U);
204 |
205 | int center = (size - 1) / 2;
206 |
207 | if (ui->customRadioButton->isChecked()) {
208 | // TODO
209 | structuringElement.at(center, center) = 255;
210 | } else if (ui->crossRadioButton->isChecked()) {
211 | for (int i = 0; i < size; i++)
212 | for (int j = 0; j < size; j++)
213 | if ((i == center) || (j == center))
214 | structuringElement.at(i, j) = 255;
215 | } else if (ui->diskRadioButton->isChecked()) {
216 | int squaredRadius = center * center;
217 |
218 | for (int i = 0; i < size; i++)
219 | for (int j = 0; j < size; j++)
220 | if (((i - center) * (i - center) +
221 | (j - center) * (j - center)) <=
222 | squaredRadius)
223 | structuringElement.at(i, j) = 255;
224 | } else if (ui->xRadioButton->isChecked()) {
225 | for (int i = 0; i < size; i++)
226 | for (int j = 0; j < size; j++)
227 | if ((i == j) || (i == (size - j - 1)))
228 | structuringElement.at(i, j) = 255;
229 | }
230 | }
231 |
232 | QPixmap pixmap = QPixmap::fromImage(Mat2QImage(structuringElement));
233 | QSize labelSize = ui->structuringElementLabel->size();
234 |
235 | ui->structuringElementLabel->setPixmap(pixmap.scaled(labelSize,
236 | Qt::KeepAspectRatio));
237 | }
238 |
--------------------------------------------------------------------------------
/morphologywindow.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Jorge Aparicio
3 | *
4 | * This file is part of ImageQ.
5 | *
6 | * ImageQ is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 |
11 | * ImageQ is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 |
16 | * You should have received a copy of the GNU General Public License
17 | * along with ImageQ. If not, see .
18 | */
19 |
20 | #pragma once
21 |
22 | #include
23 |
24 | #include
25 |
26 | class Image;
27 |
28 | namespace Ui {
29 | class MorphologyWindow;
30 | }
31 |
32 | class MorphologyWindow : public QMainWindow
33 | {
34 | Q_OBJECT
35 |
36 | public:
37 | explicit MorphologyWindow(Image* image,
38 | QWidget *parent = 0);
39 | ~MorphologyWindow();
40 |
41 | signals:
42 | void update();
43 |
44 | protected:
45 | void closeEvent(QCloseEvent *);
46 |
47 | private slots:
48 | void on_cancelPushButton_clicked();
49 | void on_okPushButton_clicked();
50 |
51 | void on_closeRadioButton_toggled(bool);
52 | void on_crossRadioButton_toggled(bool);
53 | void on_dilateRadioButton_toggled(bool);
54 | void on_diskRadioButton_toggled(bool);
55 | void on_erodeRadioButton_toggled(bool);
56 | void on_openRadioButton_toggled(bool);
57 | void on_squareRadioButton_toggled(bool);
58 | void on_xRadioButton_toggled(bool);
59 |
60 | void on_iterationsSpinBox_valueChanged(int);
61 | void on_sizeSpinBox_valueChanged(int);
62 |
63 | void on_customRadioButton_toggled(bool checked);
64 |
65 | private:
66 | Ui::MorphologyWindow *ui;
67 | Image* image;
68 | cv::Mat structuringElement;
69 | bool abort;
70 |
71 | void morphology();
72 | void updateStructuringElement();
73 | };
74 |
--------------------------------------------------------------------------------
/morphologywindow.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | MorphologyWindow
4 |
5 |
6 |
7 | 0
8 | 0
9 | 499
10 | 338
11 |
12 |
13 |
14 | Morphology
15 |
16 |
17 |
18 | -
19 |
20 |
21 | IMAGE
22 |
23 |
24 | Qt::AlignCenter
25 |
26 |
27 |
28 | -
29 |
30 |
31 | Operation
32 |
33 |
34 |
-
35 |
36 |
37 | Dilate
38 |
39 |
40 | true
41 |
42 |
43 |
44 | -
45 |
46 |
47 | Erode
48 |
49 |
50 |
51 | -
52 |
53 |
54 | Close
55 |
56 |
57 |
58 | -
59 |
60 |
61 | Open
62 |
63 |
64 |
65 |
66 |
67 |
68 | -
69 |
70 |
71 | Kernel size
72 |
73 |
74 |
75 | -
76 |
77 |
78 | 3
79 |
80 |
81 | 2
82 |
83 |
84 |
85 | -
86 |
87 |
88 | Iterations:
89 |
90 |
91 |
92 | -
93 |
94 |
95 | 1
96 |
97 |
98 |
99 | -
100 |
101 |
102 | Structuring Element
103 |
104 |
105 |
-
106 |
107 |
108 | Cross
109 |
110 |
111 |
112 | -
113 |
114 |
115 | Custom
116 |
117 |
118 |
119 | -
120 |
121 |
122 | Disk
123 |
124 |
125 |
126 | -
127 |
128 |
129 | X
130 |
131 |
132 |
133 | -
134 |
135 |
136 | Square
137 |
138 |
139 | true
140 |
141 |
142 |
143 |
144 |
145 |
146 | -
147 |
148 |
149 | OK
150 |
151 |
152 |
153 | -
154 |
155 |
156 | Cancel
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
--------------------------------------------------------------------------------
/opencv_future/imgproc/connectedcomponents.hpp:
--------------------------------------------------------------------------------
1 | /*M///////////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 | //
5 | // By downloading, copying, installing or using the software you agree to this license.
6 | // If you do not agree to this license, do not download, install,
7 | // copy or use the software.
8 | //
9 | //
10 | // Intel License Agreement
11 | // For Open Source Computer Vision Library
12 | //
13 | // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 | // Third party copyrights are property of their respective owners.
15 | //
16 | // Redistribution and use in source and binary forms, with or without modification,
17 | // are permitted provided that the following conditions are met:
18 | //
19 | // * Redistribution's of source code must retain the above copyright notice,
20 | // this list of conditions and the following disclaimer.
21 | //
22 | // * Redistribution's in binary form must reproduce the above copyright notice,
23 | // this list of conditions and the following disclaimer in the documentation
24 | // and/or other materials provided with the distribution.
25 | //
26 | // * The name of Intel Corporation may not be used to endorse or promote products
27 | // derived from this software without specific prior written permission.
28 | //
29 | // This software is provided by the copyright holders and contributors "as is" and
30 | // any express or implied warranties, including, but not limited to, the implied
31 | // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 | // In no event shall the Intel Corporation or contributors be liable for any direct,
33 | // indirect, incidental, special, exemplary, or consequential damages
34 | // (including, but not limited to, procurement of substitute goods or services;
35 | // loss of use, data, or profits; or business interruption) however caused
36 | // and on any theory of liability, whether in contract, strict liability,
37 | // or tort (including negligence or otherwise) arising in any way out of
38 | // the use of this software, even if advised of the possibility of such damage.
39 | //
40 | // 2011 Jason Newton
41 | //M*/
42 | //
43 |
44 | #pragma once
45 |
46 | #include
47 |
48 | namespace cv {
49 | struct CV_EXPORTS ConnectedComponentStats
50 | {
51 | int lower_x;//!< lower left corner column
52 | int lower_y;//!< lower left corner row
53 | int upper_x;//!< upper right corner column
54 | int upper_y;//!< upper right corner row
55 | double centroid_x;//!< centroid column
56 | double centroid_y;//!< centroid row
57 | uint64 integral_x;//!< sum of all columns where the image was non-zero
58 | uint64 integral_y;//!< sum of all rows where the image was non-zero
59 | unsigned int area;//!< count of all non-zero pixels
60 | };
61 |
62 | CV_EXPORTS_W int connectedComponents(CV_OUT Mat &L, const Mat &I, int connectivity = 8);
63 | CV_EXPORTS_W int connectedComponentsWithStats(CV_OUT Mat &L, const Mat &I, CV_OUT std::vector &statsv, int connectivity = 8);
64 | }
65 |
--------------------------------------------------------------------------------
/opencv_future/imgproc/src/connectedcomponents.cpp:
--------------------------------------------------------------------------------
1 | /*M///////////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 | //
5 | // By downloading, copying, installing or using the software you agree to this license.
6 | // If you do not agree to this license, do not download, install,
7 | // copy or use the software.
8 | //
9 | //
10 | // Intel License Agreement
11 | // For Open Source Computer Vision Library
12 | //
13 | // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 | // Third party copyrights are property of their respective owners.
15 | //
16 | // Redistribution and use in source and binary forms, with or without modification,
17 | // are permitted provided that the following conditions are met:
18 | //
19 | // * Redistribution's of source code must retain the above copyright notice,
20 | // this list of conditions and the following disclaimer.
21 | //
22 | // * Redistribution's in binary form must reproduce the above copyright notice,
23 | // this list of conditions and the following disclaimer in the documentation
24 | // and/or other materials provided with the distribution.
25 | //
26 | // * The name of Intel Corporation may not be used to endorse or promote products
27 | // derived from this software without specific prior written permission.
28 | //
29 | // This software is provided by the copyright holders and contributors "as is" and
30 | // any express or implied warranties, including, but not limited to, the implied
31 | // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 | // In no event shall the Intel Corporation or contributors be liable for any direct,
33 | // indirect, incidental, special, exemplary, or consequential damages
34 | // (including, but not limited to, procurement of substitute goods or services;
35 | // loss of use, data, or profits; or business interruption) however caused
36 | // and on any theory of liability, whether in contract, strict liability,
37 | // or tort (including negligence or otherwise) arising in any way out of
38 | // the use of this software, even if advised of the possibility of such damage.
39 | //
40 | // 2011 Jason Newton
41 | //M*/
42 | //
43 |
44 | #include "../connectedcomponents.hpp"
45 |
46 | #include
47 |
48 | namespace cv{
49 | namespace connectedcomponents{
50 |
51 | template
52 | struct NoOp{
53 | NoOp(){
54 | }
55 | void init(const LabelT labels){
56 | (void) labels;
57 | }
58 | inline
59 | void operator()(int r, int c, LabelT l){
60 | (void) r;
61 | (void) c;
62 | (void) l;
63 | }
64 | void finish(){}
65 | };
66 | template
67 | struct CCStatsOp{
68 | std::vector &statsv;
69 | CCStatsOp(std::vector &_statsv): statsv(_statsv){
70 | }
71 | inline
72 | void init(const LabelT nlabels){
73 | statsv.clear();
74 | cv::ConnectedComponentStats stats = cv::ConnectedComponentStats();
75 | stats.lower_x = std::numeric_limits::max();
76 | stats.lower_y = std::numeric_limits::max();
77 | stats.upper_x = std::numeric_limits::min();
78 | stats.upper_y = std::numeric_limits::min();
79 | stats.centroid_x = 0;
80 | stats.centroid_y = 0;
81 | stats.integral_x = 0;
82 | stats.integral_y = 0;
83 | stats.area = 0;
84 | statsv.resize(nlabels, stats);
85 | }
86 | void operator()(int r, int c, LabelT l){
87 | ConnectedComponentStats &stats = statsv[l];
88 | if(c > stats.upper_x){
89 | stats.upper_x = c;
90 | }else{
91 | if(c < stats.lower_x){
92 | stats.lower_x = c;
93 | }
94 | }
95 | if(r > stats.upper_y){
96 | stats.upper_y = r;
97 | }else{
98 | if(r < stats.lower_y){
99 | stats.lower_y = r;
100 | }
101 | }
102 | stats.integral_x += c;
103 | stats.integral_y += r;
104 | stats.area++;
105 | }
106 | void finish(){
107 | for(size_t l = 0; l < statsv.size(); ++l){
108 | ConnectedComponentStats &stats = statsv[l];
109 | stats.lower_x = std::min(stats.lower_x, stats.upper_x);
110 | stats.lower_y = std::min(stats.lower_y, stats.upper_y);
111 | stats.centroid_x = stats.integral_x / double(stats.area);
112 | stats.centroid_y = stats.integral_y / double(stats.area);
113 | }
114 | }
115 | };
116 |
117 | //Find the root of the tree of node i
118 | template
119 | inline static
120 | LabelT findRoot(const LabelT *P, LabelT i){
121 | LabelT root = i;
122 | while(P[root] < root){
123 | root = P[root];
124 | }
125 | return root;
126 | }
127 |
128 | //Make all nodes in the path of node i point to root
129 | template
130 | inline static
131 | void setRoot(LabelT *P, LabelT i, LabelT root){
132 | while(P[i] < i){
133 | LabelT j = P[i];
134 | P[i] = root;
135 | i = j;
136 | }
137 | P[i] = root;
138 | }
139 |
140 | //Find the root of the tree of the node i and compress the path in the process
141 | template
142 | inline static
143 | LabelT find(LabelT *P, LabelT i){
144 | LabelT root = findRoot(P, i);
145 | setRoot(P, i, root);
146 | return root;
147 | }
148 |
149 | //unite the two trees containing nodes i and j and return the new root
150 | template
151 | inline static
152 | LabelT set_union(LabelT *P, LabelT i, LabelT j){
153 | LabelT root = findRoot(P, i);
154 | if(i != j){
155 | LabelT rootj = findRoot(P, j);
156 | if(root > rootj){
157 | root = rootj;
158 | }
159 | setRoot(P, j, root);
160 | }
161 | setRoot(P, i, root);
162 | return root;
163 | }
164 |
165 | //Flatten the Union Find tree and relabel the components
166 | template
167 | inline static
168 | LabelT flattenL(LabelT *P, LabelT length){
169 | LabelT k = 1;
170 | for(LabelT i = 1; i < length; ++i){
171 | if(P[i] < i){
172 | P[i] = P[P[i]];
173 | }else{
174 | P[i] = k; k = k + 1;
175 | }
176 | }
177 | return k;
178 | }
179 |
180 | //Based on "Two Strategies to Speed up Connected Components Algorithms", the SAUF (Scan array union find) variant
181 | //using decision trees
182 | //Kesheng Wu, et al
183 | //Note: rows are encoded as position in the "rows" array to save lookup times
184 | //reference for 4-way: {{-1, 0}, {0, -1}};//b, d neighborhoods
185 | const int G4[2][2] = {{1, 0}, {0, -1}};//b, d neighborhoods
186 | //reference for 8-way: {{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}};//a, b, c, d neighborhoods
187 | const int G8[4][2] = {{1, -1}, {1, 0}, {1, 1}, {0, -1}};//a, b, c, d neighborhoods
188 | template, int connectivity = 8>
189 | struct LabelingImpl{
190 | LabelT operator()(Mat &L, const Mat &I, StatsOp &sop){
191 | const int rows = L.rows;
192 | const int cols = L.cols;
193 | size_t Plength = (size_t(rows + 3 - 1)/3) * (size_t(cols + 3 - 1)/3);
194 | if(connectivity == 4){
195 | Plength = 4 * Plength;//a quick and dirty upper bound, an exact answer exists if you want to find it
196 | //the 4 comes from the fact that a 3x3 block can never have more than 4 unique labels
197 | }
198 | LabelT *P = (LabelT *) fastMalloc(sizeof(LabelT) * Plength);
199 | P[0] = 0;
200 | LabelT lunique = 1;
201 | //scanning phase
202 | for(int r_i = 0; r_i < rows; ++r_i){
203 | LabelT *Lrow = (LabelT *)(L.data + L.step.p[0] * r_i);
204 | LabelT *Lrow_prev = (LabelT *)(((char *)Lrow) - L.step.p[0]);
205 | const PixelT *Irow = (PixelT *)(I.data + I.step.p[0] * r_i);
206 | const PixelT *Irow_prev = (const PixelT *)(((char *)Irow) - I.step.p[0]);
207 | LabelT *Lrows[2] = {
208 | Lrow,
209 | Lrow_prev
210 | };
211 | const PixelT *Irows[2] = {
212 | Irow,
213 | Irow_prev
214 | };
215 | if(connectivity == 8){
216 | const int a = 0;
217 | const int b = 1;
218 | const int c = 2;
219 | const int d = 3;
220 | const bool T_a_r = (r_i - G8[a][0]) >= 0;
221 | const bool T_b_r = (r_i - G8[b][0]) >= 0;
222 | const bool T_c_r = (r_i - G8[c][0]) >= 0;
223 | for(int c_i = 0; Irows[0] != Irow + cols; ++Irows[0], c_i++){
224 | if(!*Irows[0]){
225 | Lrow[c_i] = 0;
226 | continue;
227 | }
228 | Irows[1] = Irow_prev + c_i;
229 | Lrows[0] = Lrow + c_i;
230 | Lrows[1] = Lrow_prev + c_i;
231 | const bool T_a = T_a_r && (c_i + G8[a][1]) >= 0 && *(Irows[G8[a][0]] + G8[a][1]);
232 | const bool T_b = T_b_r && *(Irows[G8[b][0]] + G8[b][1]);
233 | const bool T_c = T_c_r && (c_i + G8[c][1]) < cols && *(Irows[G8[c][0]] + G8[c][1]);
234 | const bool T_d = (c_i + G8[d][1]) >= 0 && *(Irows[G8[d][0]] + G8[d][1]);
235 |
236 | //decision tree
237 | if(T_b){
238 | //copy(b)
239 | *Lrows[0] = *(Lrows[G8[b][0]] + G8[b][1]);
240 | }else{//not b
241 | if(T_c){
242 | if(T_a){
243 | //copy(c, a)
244 | *Lrows[0] = set_union(P, *(Lrows[G8[c][0]] + G8[c][1]), *(Lrows[G8[a][0]] + G8[a][1]));
245 | }else{
246 | if(T_d){
247 | //copy(c, d)
248 | *Lrows[0] = set_union(P, *(Lrows[G8[c][0]] + G8[c][1]), *(Lrows[G8[d][0]] + G8[d][1]));
249 | }else{
250 | //copy(c)
251 | *Lrows[0] = *(Lrows[G8[c][0]] + G8[c][1]);
252 | }
253 | }
254 | }else{//not c
255 | if(T_a){
256 | //copy(a)
257 | *Lrows[0] = *(Lrows[G8[a][0]] + G8[a][1]);
258 | }else{
259 | if(T_d){
260 | //copy(d)
261 | *Lrows[0] = *(Lrows[G8[d][0]] + G8[d][1]);
262 | }else{
263 | //new label
264 | *Lrows[0] = lunique;
265 | P[lunique] = lunique;
266 | lunique = lunique + 1;
267 | }
268 | }
269 | }
270 | }
271 | }
272 | }else{
273 | //B & D only
274 | assert(connectivity == 4);
275 | const int b = 0;
276 | const int d = 1;
277 | const bool T_b_r = (r_i - G4[b][0]) >= 0;
278 | for(int c_i = 0; Irows[0] != Irow + cols; ++Irows[0], c_i++){
279 | if(!*Irows[0]){
280 | Lrow[c_i] = 0;
281 | continue;
282 | }
283 | Irows[1] = Irow_prev + c_i;
284 | Lrows[0] = Lrow + c_i;
285 | Lrows[1] = Lrow_prev + c_i;
286 | const bool T_b = T_b_r && *(Irows[G4[b][0]] + G4[b][1]);
287 | const bool T_d = (c_i + G4[d][1]) >= 0 && *(Irows[G4[d][0]] + G4[d][1]);
288 | if(T_b){
289 | if(T_d){
290 | //copy(d, b)
291 | *Lrows[0] = set_union(P, *(Lrows[G4[d][0]] + G4[d][1]), *(Lrows[G4[b][0]] + G4[b][1]));
292 | }else{
293 | //copy(b)
294 | *Lrows[0] = *(Lrows[G4[b][0]] + G4[b][1]);
295 | }
296 | }else{
297 | if(T_d){
298 | //copy(d)
299 | *Lrows[0] = *(Lrows[G4[d][0]] + G4[d][1]);
300 | }else{
301 | //new label
302 | *Lrows[0] = lunique;
303 | P[lunique] = lunique;
304 | lunique = lunique + 1;
305 | }
306 | }
307 | }
308 | }
309 | }
310 |
311 | //analysis
312 | LabelT nLabels = flattenL(P, lunique);
313 | sop.init(nLabels);
314 |
315 | for(int r_i = 0; r_i < rows; ++r_i){
316 | LabelT *Lrow_start = (LabelT *)(L.data + L.step.p[0] * r_i);
317 | LabelT *Lrow_end = Lrow_start + cols;
318 | LabelT *Lrow = Lrow_start;
319 | for(int c_i = 0; Lrow != Lrow_end; ++Lrow, ++c_i){
320 | const LabelT l = P[*Lrow];
321 | *Lrow = l;
322 | sop(r_i, c_i, l);
323 | }
324 | }
325 |
326 | sop.finish();
327 | fastFree(P);
328 |
329 | return nLabels;
330 | }//End function LabelingImpl operator()
331 |
332 | };//End struct LabelingImpl
333 | }//end namespace connectedcomponents
334 |
335 | //L's type must have an appropriate depth for the number of pixels in I
336 | template
337 | int connectedComponents_sub1(Mat &L, const Mat &I, int connectivity, StatsOp &sop){
338 | CV_Assert(L.rows == I.rows);
339 | CV_Assert(L.cols == I.cols);
340 | CV_Assert(L.channels() == 1 && I.channels() == 1);
341 | CV_Assert(connectivity == 8 || connectivity == 4);
342 |
343 | int lDepth = L.depth();
344 | int iDepth = I.depth();
345 | using connectedcomponents::LabelingImpl;
346 | //warn if L's depth is not sufficient?
347 |
348 | if(lDepth == CV_8U){
349 | if(iDepth == CV_8U || iDepth == CV_8S){
350 | if(connectivity == 4){
351 | return (int) LabelingImpl()(L, I, sop);
352 | }else{
353 | return (int) LabelingImpl()(L, I, sop);
354 | }
355 | }else{
356 | CV_Assert(false);
357 | }
358 | }else if(lDepth == CV_16U){
359 | if(iDepth == CV_8U || iDepth == CV_8S){
360 | if(connectivity == 4){
361 | return (int) LabelingImpl()(L, I, sop);
362 | }else{
363 | return (int) LabelingImpl()(L, I, sop);
364 | }
365 | }else{
366 | CV_Assert(false);
367 | }
368 | }else if(lDepth == CV_32S){
369 | //note that signed types don't really make sense here and not being able to use uint32_t matters for scientific projects
370 | //OpenCV: how should we proceed? .at typechecks in debug mode
371 | if(iDepth == CV_8U || iDepth == CV_8S){
372 | if(connectivity == 4){
373 | return (int) LabelingImpl()(L, I, sop);
374 | }else{
375 | return (int) LabelingImpl()(L, I, sop);
376 | }
377 | }else{
378 | CV_Assert(false);
379 | }
380 | }
381 |
382 | CV_Error(CV_StsUnsupportedFormat, "unsupported label/image type");
383 | return -1;
384 | }
385 |
386 | int connectedComponents(Mat &L, const Mat &I, int connectivity){
387 | int lDepth = L.depth();
388 | if(lDepth == CV_8U){
389 | connectedcomponents::NoOp sop; return connectedComponents_sub1(L, I, connectivity, sop);
390 | }else if(lDepth == CV_16U){
391 | connectedcomponents::NoOp sop; return connectedComponents_sub1(L, I, connectivity, sop);
392 | }else if(lDepth == CV_32S){
393 | connectedcomponents::NoOp sop; return connectedComponents_sub1(L, I, connectivity, sop);
394 | }else{
395 | CV_Assert(false);
396 | return 0;
397 | }
398 | }
399 |
400 | int connectedComponentsWithStats(Mat &L, const Mat &I, std::vector &statsv, int connectivity){
401 | int lDepth = L.depth();
402 | if(lDepth == CV_8U){
403 | connectedcomponents::CCStatsOp sop(statsv); return connectedComponents_sub1(L, I, connectivity, sop);
404 | }else if(lDepth == CV_16U){
405 | connectedcomponents::CCStatsOp sop(statsv); return connectedComponents_sub1(L, I, connectivity, sop);
406 | }else if(lDepth == CV_32S){
407 | connectedcomponents::CCStatsOp sop(statsv); return connectedComponents_sub1(L, I, connectivity, sop);
408 | }else{
409 | CV_Assert(false);
410 | return 0;
411 | }
412 | }
413 |
414 | }
415 |
--------------------------------------------------------------------------------
/samples/N2_2.kesit.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JorgeAparicio/ImageQ/2af15369636e73c44dbb76c2f81b0c609ca5ff64/samples/N2_2.kesit.JPG
--------------------------------------------------------------------------------
/samples/Nanofilaments-EMpicture.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JorgeAparicio/ImageQ/2af15369636e73c44dbb76c2f81b0c609ca5ff64/samples/Nanofilaments-EMpicture.jpg
--------------------------------------------------------------------------------
/samples/Pos.tif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JorgeAparicio/ImageQ/2af15369636e73c44dbb76c2f81b0c609ca5ff64/samples/Pos.tif
--------------------------------------------------------------------------------
/samples/Sand_from_Gobi_Desert.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JorgeAparicio/ImageQ/2af15369636e73c44dbb76c2f81b0c609ca5ff64/samples/Sand_from_Gobi_Desert.jpg
--------------------------------------------------------------------------------
/samples/license.txt:
--------------------------------------------------------------------------------
1 | The images in this folder belong to public domain or are licensed under
2 | Creative commons.
3 |
4 | + File: N2_2.kesit.JPG
5 | + Author: aslamacia
6 | + License: Public domain
7 | + Link: http://commons.wikimedia.org/wiki/File:N2_2.kesit.JPG
8 |
9 | + File: Nanofilaments-EMpicture.jpg
10 | + Author: Friedrich1997
11 | + License: Creative Commons Attribution 3.0 Unported
12 | + Link: http://commons.wikimedia.org/wiki/File:Nanofilaments-EMpicture.jpg
13 |
14 | + File: Pos.tif
15 | + Author: Chivesud
16 | + License: Creative Commons Attribution-Share Alike 3.0 Unported
17 | + Link: http://commons.wikimedia.org/wiki/File:Pos.tif
18 |
19 | + File: Sand_from_Gobi_Desert.jpg
20 | + Author: Siim Sepp
21 | + License: Creative Commons Attribution-Share Alike 3.0 Unported
22 | + Link: http://commons.wikimedia.org/wiki/File:Sand_from_Gobi_Desert.jpg
23 |
24 |
--------------------------------------------------------------------------------
/setscalewindow.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Jorge Aparicio
3 | *
4 | * This file is part of ImageQ.
5 | *
6 | * ImageQ is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 |
11 | * ImageQ is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 |
16 | * You should have received a copy of the GNU General Public License
17 | * along with ImageQ. If not, see .
18 | */
19 |
20 |
21 | #include "setscalewindow.h"
22 | #include "ui_setscalewindow.h"
23 |
24 | #include "image.h"
25 |
26 | SetScaleWindow::SetScaleWindow(Image* image,
27 | QWidget *parent) :
28 | QMainWindow(parent),
29 | ui(new Ui::SetScaleWindow),
30 | image(image)
31 | {
32 | ui->setupUi(this);
33 |
34 | ui->unitLineEdit->setValidator(new QRegExpValidator(QRegExp("[a-zA-Z]+")));
35 |
36 | scale = image->scale;
37 |
38 | showConversion();
39 |
40 | this->setAttribute(Qt::WA_DeleteOnClose);
41 |
42 | this->show();
43 | }
44 |
45 | SetScaleWindow::~SetScaleWindow()
46 | {
47 | delete ui;
48 | }
49 |
50 | void SetScaleWindow::on_lengthSpinBox_valueChanged(int)
51 | {
52 | updateConversion();
53 | }
54 |
55 | void SetScaleWindow::on_unitLineEdit_textEdited(const QString &)
56 | {
57 | if (ui->unitLineEdit->hasAcceptableInput())
58 | updateConversion();
59 | }
60 |
61 | void SetScaleWindow::on_selectPushButton_clicked()
62 | {
63 | image->setSelectionMode(Image::Line);
64 |
65 | connect(image, SIGNAL(lineSelected(QLine const&)),
66 | this, SLOT(on_lineSelected(QLine const&)));
67 |
68 | this->hide();
69 | }
70 |
71 | void SetScaleWindow::on_okPushButton_clicked()
72 | {
73 | image->scale = scale;
74 |
75 | this->close();
76 | }
77 |
78 | void SetScaleWindow::on_lineSelected(QLine const& line)
79 | {
80 | int distance = sqrt(pow(line.dx(), 2) + pow(line.dy(), 2)) + 1;
81 |
82 | ui->pixelsLabel->setText(QString::number(distance));
83 | image->setSelectionMode(Image::None);
84 |
85 | this->show();
86 | image->update();
87 |
88 | disconnect(image, SIGNAL(lineSelected(QLine const&)),
89 | this, SLOT(on_lineSelected(QLine const&)));
90 |
91 | updateConversion();
92 | }
93 |
94 | void SetScaleWindow::showConversion() const
95 | {
96 | ui->scaleLabel->setText(QString::number(scale, 'g', 4) +
97 | ' ' + image->unit);
98 | }
99 |
100 | void SetScaleWindow::updateConversion()
101 | {
102 | scale = ui->lengthSpinBox->value() / ui->pixelsLabel->text().toFloat();
103 | image->unit = ui->unitLineEdit->text();
104 |
105 | showConversion();
106 | }
107 |
--------------------------------------------------------------------------------
/setscalewindow.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Jorge Aparicio
3 | *
4 | * This file is part of ImageQ.
5 | *
6 | * ImageQ is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 |
11 | * ImageQ is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 |
16 | * You should have received a copy of the GNU General Public License
17 | * along with ImageQ. If not, see .
18 | */
19 |
20 | #pragma once
21 |
22 | #include
23 |
24 | namespace Ui {
25 | class SetScaleWindow;
26 | }
27 |
28 | class Image;
29 |
30 | class SetScaleWindow : public QMainWindow
31 | {
32 | Q_OBJECT
33 |
34 | public:
35 | explicit SetScaleWindow(Image* image,
36 | QWidget *parent = 0);
37 | ~SetScaleWindow();
38 |
39 | private slots:
40 | void on_lengthSpinBox_valueChanged(int);
41 | void on_unitLineEdit_textEdited(const QString &);
42 |
43 | void on_selectPushButton_clicked();
44 | void on_okPushButton_clicked();
45 |
46 | void on_lineSelected(QLine const& line);
47 |
48 | private:
49 | Ui::SetScaleWindow *ui;
50 | Image* image;
51 | float scale;
52 |
53 | void updateConversion();
54 | void showConversion() const;
55 | };
56 |
--------------------------------------------------------------------------------
/setscalewindow.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | SetScaleWindow
4 |
5 |
6 |
7 | 0
8 | 0
9 | 301
10 | 133
11 |
12 |
13 |
14 | Set Scale
15 |
16 |
17 |
18 | -
19 |
20 |
-
21 |
22 |
23 | Scale: 1 pixel <->
24 |
25 |
26 |
27 | -
28 |
29 |
30 | 1 m
31 |
32 |
33 | Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
34 |
35 |
36 |
37 | -
38 |
39 |
40 | Qt::Horizontal
41 |
42 |
43 |
44 | 40
45 | 20
46 |
47 |
48 |
49 |
50 |
51 |
52 | -
53 |
54 |
-
55 |
56 |
57 | Pixels:
58 |
59 |
60 |
61 | -
62 |
63 |
64 | 1
65 |
66 |
67 | Qt::AlignCenter
68 |
69 |
70 |
71 |
72 |
73 | -
74 |
75 |
-
76 |
77 |
78 |
79 |
80 |
81 |
82 | -
83 |
84 |
85 | <->
86 |
87 |
88 |
89 |
90 |
91 | -
92 |
93 |
-
94 |
95 |
96 | Length:
97 |
98 |
99 |
100 | -
101 |
102 |
103 | Qt::AlignCenter
104 |
105 |
106 | 1
107 |
108 |
109 | 1000
110 |
111 |
112 |
113 |
114 |
115 | -
116 |
117 |
-
118 |
119 |
120 | Unit:
121 |
122 |
123 |
124 | -
125 |
126 |
127 | m
128 |
129 |
130 | Qt::AlignCenter
131 |
132 |
133 |
134 |
135 |
136 | -
137 |
138 |
-
139 |
140 |
141 | Select
142 |
143 |
144 |
145 | -
146 |
147 |
148 | Qt::Horizontal
149 |
150 |
151 |
152 | 40
153 | 20
154 |
155 |
156 |
157 |
158 | -
159 |
160 |
161 | OK
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
--------------------------------------------------------------------------------
/textlistwindow.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Jorge Aparicio
3 | *
4 | * This file is part of ImageQ.
5 | *
6 | * ImageQ is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 |
11 | * ImageQ is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 |
16 | * You should have received a copy of the GNU General Public License
17 | * along with ImageQ. If not, see .
18 | */
19 |
20 | #include "textlistwindow.h"
21 | #include "ui_textlistwindow.h"
22 |
23 | #include
24 | #include
25 |
26 | TextListWindow::TextListWindow(QString const& title,
27 | QString const& header,
28 | QWidget *parent) :
29 | QMainWindow(parent),
30 | ui(new Ui::TextListWindow),
31 | text(QStringList()),
32 | count(0)
33 | {
34 | ui->setupUi(this);
35 |
36 | this->setWindowTitle(title);
37 |
38 | ui->headerLabel->setText(header);
39 |
40 | this->setAttribute(Qt::WA_DeleteOnClose);
41 | this->show();
42 | }
43 |
44 | TextListWindow::~TextListWindow()
45 | {
46 | delete ui;
47 | }
48 |
49 | void TextListWindow::append(QString const& s)
50 | {
51 | count++;
52 |
53 | text << s;
54 |
55 | ui->textLabel->setText(text.join(QString('\n')));
56 | }
57 |
58 | int TextListWindow::size() const
59 | {
60 | return count;
61 | }
62 |
63 | void TextListWindow::on_savePushButton_clicked()
64 | {
65 | QString filename = QFileDialog::getSaveFileName(this,
66 | QLatin1String("Save"),
67 | QString(),
68 | "Text Files (*.txt)");
69 |
70 | if (!filename.endsWith(".txt"))
71 | filename += ".txt";
72 |
73 | QFile f(filename);
74 | f.open(QIODevice::WriteOnly);
75 | QTextStream stream(&f);
76 |
77 | stream << ui->headerLabel->text() + "\n" + text.join("\n");
78 |
79 | f.close();
80 |
81 | this->close();
82 | }
83 |
84 | void TextListWindow::on_closePushButton_clicked()
85 | {
86 | this->close();
87 | }
88 |
--------------------------------------------------------------------------------
/textlistwindow.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Jorge Aparicio
3 | *
4 | * This file is part of ImageQ.
5 | *
6 | * ImageQ is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 |
11 | * ImageQ is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 |
16 | * You should have received a copy of the GNU General Public License
17 | * along with ImageQ. If not, see .
18 | */
19 |
20 | #pragma once
21 |
22 | #include
23 |
24 | namespace Ui {
25 | class TextListWindow;
26 | }
27 |
28 | class TextListWindow : public QMainWindow
29 | {
30 | Q_OBJECT
31 |
32 | public:
33 | explicit TextListWindow(QString const& title,
34 | QString const& header,
35 | QWidget *parent = 0);
36 | ~TextListWindow();
37 | void append(QString const& s);
38 | int size() const;
39 |
40 | private slots:
41 | void on_savePushButton_clicked();
42 |
43 | void on_closePushButton_clicked();
44 |
45 | private:
46 | Ui::TextListWindow *ui;
47 | QStringList text;
48 | int count;
49 | };
50 |
--------------------------------------------------------------------------------
/textlistwindow.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | TextListWindow
4 |
5 |
6 |
7 | 0
8 | 0
9 | 242
10 | 131
11 |
12 |
13 |
14 | MainWindow
15 |
16 |
17 |
18 | -
19 |
20 |
21 | true
22 |
23 |
24 |
25 |
26 | 0
27 | 0
28 | 222
29 | 76
30 |
31 |
32 |
33 |
-
34 |
35 |
36 |
37 |
38 |
39 |
40 | -
41 |
42 |
43 | Header
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | -
52 |
53 |
-
54 |
55 |
56 | Save
57 |
58 |
59 |
60 | -
61 |
62 |
63 | Qt::Horizontal
64 |
65 |
66 |
67 | 40
68 | 20
69 |
70 |
71 |
72 |
73 | -
74 |
75 |
76 | Close
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/thresholdwindow.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Jorge Aparicio
3 | *
4 | * This file is part of ImageQ.
5 | *
6 | * ImageQ is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 |
11 | * ImageQ is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 |
16 | * You should have received a copy of the GNU General Public License
17 | * along with ImageQ. If not, see .
18 | */
19 |
20 | #include "thresholdwindow.h"
21 | #include "ui_thresholdwindow.h"
22 |
23 | #include "image.h"
24 |
25 | #include
26 |
27 | #include
28 |
29 | ThresholdWindow::ThresholdWindow(Image* image,
30 | QWidget *parent) :
31 | QMainWindow(parent),
32 | ui(new Ui::ThresholdWindow),
33 | image(image),
34 | histogram(image->current, 256),
35 | yAxis(0),
36 | abort(true)
37 | {
38 | ui->setupUi(this);
39 |
40 | image->backup();
41 |
42 | connect(this, SIGNAL(update()),
43 | image, SLOT(update()));
44 |
45 | histogram.attach(ui->histogramPlot);
46 |
47 | ui->histogramPlot->setAxisAutoScale(QwtPlot::xBottom, false);
48 | ui->histogramPlot->setAxisScale(QwtPlot::xBottom, 0, 256);
49 |
50 | ui->histogramPlot->enableAxis(QwtPlot::xBottom, false);
51 | ui->histogramPlot->enableAxis(QwtPlot::yLeft, false);
52 |
53 | this->setAttribute(Qt::WA_DeleteOnClose);
54 |
55 | ui->histogramPlot->setFixedSize(480, 200);
56 | ui->adaptativeFrame->hide();
57 | this->adjustSize();
58 | this->setFixedSize(this->size());
59 |
60 | this->show();
61 |
62 | threshold();
63 | }
64 |
65 | ThresholdWindow::~ThresholdWindow()
66 | {
67 | delete ui;
68 | }
69 |
70 | void ThresholdWindow::closeEvent(QCloseEvent *)
71 | {
72 | if (abort)
73 | image->undo();
74 | }
75 |
76 | void ThresholdWindow::on_cancelPushButton_clicked()
77 | {
78 | this->close();
79 | }
80 |
81 | void ThresholdWindow::on_okPushButton_clicked()
82 | {
83 | abort = false;
84 |
85 | this->close();
86 | }
87 |
88 | void ThresholdWindow::on_thresholdSlider_sliderMoved(int value)
89 | {
90 | if (yAxis) {
91 | delete yAxis;
92 | yAxis = 0;
93 | }
94 |
95 | if (!ui->adaptativeCheckBox->isChecked()) {
96 | yAxis = new QwtPlotMarker;
97 |
98 | yAxis->setLineStyle(QwtPlotMarker::VLine);
99 | yAxis->setLinePen(QPen(Qt::red));
100 | yAxis->setXValue(value + 0.5);
101 | yAxis->attach(ui->histogramPlot);
102 |
103 | ui->histogramPlot->replot();
104 | }
105 | threshold();
106 | }
107 |
108 | void ThresholdWindow::on_adaptativeCheckBox_toggled(bool checked)
109 | {
110 | ui->otsuCheckBox->setDisabled(checked);
111 |
112 | if (checked) {
113 | if (yAxis) {
114 | delete yAxis;
115 | yAxis = 0;
116 |
117 | ui->histogramPlot->replot();
118 | }
119 |
120 | ui->otsuCheckBox->setChecked(false);
121 |
122 | ui->adaptativeFrame->show();
123 | ui->nonAdaptativeFrame->hide();
124 |
125 | ui->thresholdSlider->setMinimum(-128);
126 | ui->thresholdSlider->setMaximum(127);
127 | } else {
128 | ui->adaptativeFrame->hide();
129 | ui->nonAdaptativeFrame->show();
130 |
131 | ui->thresholdSlider->setMinimum(0);
132 | ui->thresholdSlider->setMaximum(255);
133 | }
134 |
135 | ui->thresholdSlider->setValue(0);
136 |
137 | threshold();
138 | }
139 |
140 | void ThresholdWindow::on_invertedCheckBox_toggled(bool)
141 | {
142 | threshold();
143 | }
144 |
145 | void ThresholdWindow::on_otsuCheckBox_toggled(bool checked)
146 | {
147 | ui->thresholdSlider->setDisabled(checked);
148 |
149 | threshold();
150 | }
151 |
152 | void ThresholdWindow::on_binaryRadioButton_toggled(bool checked)
153 | {
154 | if (checked)
155 | threshold();
156 | }
157 |
158 | void ThresholdWindow::on_gaussianRadioButton_toggled(bool checked)
159 | {
160 | if (checked)
161 | threshold();
162 | }
163 |
164 | void ThresholdWindow::on_meanRadioButton_toggled(bool checked)
165 | {
166 | if (checked)
167 | threshold();
168 | }
169 |
170 | void ThresholdWindow::on_toZeroRadioButton_toggled(bool checked)
171 | {
172 | if (checked)
173 | threshold();
174 | }
175 |
176 | void ThresholdWindow::on_truncateRadioButton_toggled(bool checked)
177 | {
178 | ui->invertedCheckBox->setDisabled(checked);
179 |
180 | if (checked) {
181 | ui->invertedCheckBox->setChecked(false);
182 |
183 | threshold();
184 | }
185 | }
186 |
187 | void ThresholdWindow::threshold()
188 | {
189 | if (ui->adaptativeCheckBox->isChecked()) {
190 | int method = 0;
191 | int type = 0;
192 |
193 | if (ui->meanRadioButton->isChecked())
194 | method = cv::ADAPTIVE_THRESH_MEAN_C;
195 | else
196 | method = cv::ADAPTIVE_THRESH_GAUSSIAN_C;
197 |
198 | if (ui->invertedCheckBox->isChecked())
199 | type = cv::THRESH_BINARY_INV;
200 | else
201 | type = cv::THRESH_BINARY;
202 |
203 | cv::adaptiveThreshold(image->previous,
204 | image->current,
205 | 255.0,
206 | method,
207 | type,
208 | ui->sizeSpinBox->value(),
209 | ui->thresholdSlider->value()
210 | );
211 | } else {
212 | int type = 0;
213 |
214 | if (ui->binaryRadioButton->isChecked()) {
215 | if (ui->invertedCheckBox->isChecked())
216 | type = cv::THRESH_BINARY_INV;
217 | else
218 | type = cv::THRESH_BINARY;
219 | } else if (ui->truncateRadioButton->isChecked()) {
220 | type = cv::THRESH_TRUNC;
221 | } else if (ui->toZeroRadioButton->isChecked()) {
222 | if (ui->invertedCheckBox->isChecked())
223 | type = cv::THRESH_TOZERO_INV;
224 | else
225 | type = cv::THRESH_TOZERO;
226 | }
227 |
228 | if (ui->otsuCheckBox->isChecked())
229 | type |= cv::THRESH_OTSU;
230 |
231 | cv::threshold(image->previous,
232 | image->current,
233 | ui->thresholdSlider->value(),
234 | 255.0,
235 | type);
236 | }
237 |
238 | emit update();
239 | }
240 |
241 | void ThresholdWindow::on_sizeSpinBox_valueChanged(int)
242 | {
243 | threshold();
244 | }
245 |
--------------------------------------------------------------------------------
/thresholdwindow.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Jorge Aparicio
3 | *
4 | * This file is part of ImageQ.
5 | *
6 | * ImageQ is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 |
11 | * ImageQ is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 |
16 | * You should have received a copy of the GNU General Public License
17 | * along with ImageQ. If not, see .
18 | */
19 |
20 | #pragma once
21 |
22 | #include
23 |
24 | #include "histogram.h"
25 |
26 | class Image;
27 |
28 | class QwtPlotMarker;
29 |
30 | namespace Ui {
31 | class ThresholdWindow;
32 | }
33 |
34 | class ThresholdWindow : public QMainWindow
35 | {
36 | Q_OBJECT
37 |
38 | public:
39 | explicit ThresholdWindow(Image*,
40 | QWidget *parent = 0);
41 | ~ThresholdWindow();
42 |
43 | signals:
44 | void update();
45 |
46 | protected:
47 | void closeEvent(QCloseEvent *);
48 |
49 | private slots:
50 | void on_cancelPushButton_clicked();
51 | void on_okPushButton_clicked();
52 |
53 | void on_thresholdSlider_sliderMoved(int);
54 |
55 | void on_adaptativeCheckBox_toggled(bool);
56 | void on_invertedCheckBox_toggled(bool);
57 | void on_otsuCheckBox_toggled(bool checked);
58 |
59 | void on_binaryRadioButton_toggled(bool);
60 | void on_gaussianRadioButton_toggled(bool);
61 | void on_meanRadioButton_toggled(bool);
62 | void on_toZeroRadioButton_toggled(bool);
63 | void on_truncateRadioButton_toggled(bool);
64 |
65 | void on_sizeSpinBox_valueChanged(int);
66 |
67 | private:
68 | Ui::ThresholdWindow *ui;
69 | Image* image;
70 | Histogram histogram;
71 | QwtPlotMarker *yAxis;
72 | bool abort;
73 |
74 | void threshold();
75 | };
76 |
--------------------------------------------------------------------------------
/thresholdwindow.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | ThresholdWindow
4 |
5 |
6 |
7 | 0
8 | 0
9 | 516
10 | 451
11 |
12 |
13 |
14 | Threshold
15 |
16 |
17 |
18 | -
19 |
20 |
-
21 |
22 |
23 | Inverted
24 |
25 |
26 |
27 | -
28 |
29 |
30 | Otsu
31 |
32 |
33 |
34 | -
35 |
36 |
37 | Adaptative
38 |
39 |
40 |
41 | -
42 |
43 |
44 | Qt::Horizontal
45 |
46 |
47 |
48 | 40
49 | 20
50 |
51 |
52 |
53 |
54 | -
55 |
56 |
57 | OK
58 |
59 |
60 |
61 | -
62 |
63 |
64 | Cancel
65 |
66 |
67 |
68 |
69 |
70 | -
71 |
72 |
73 | true
74 |
75 |
76 | QFrame::NoFrame
77 |
78 |
79 | QFrame::Plain
80 |
81 |
82 |
-
83 |
84 |
-
85 |
86 |
87 | Method
88 |
89 |
90 |
-
91 |
92 |
93 | Mean
94 |
95 |
96 | true
97 |
98 |
99 |
100 | -
101 |
102 |
103 | Gaussian
104 |
105 |
106 |
107 |
108 |
109 |
110 | -
111 |
112 |
113 | Qt::Horizontal
114 |
115 |
116 |
117 | 40
118 | 20
119 |
120 |
121 |
122 |
123 | -
124 |
125 |
126 | Kernel size:
127 |
128 |
129 |
130 | -
131 |
132 |
133 | 3
134 |
135 |
136 | 2
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 | -
146 |
147 |
148 | -
149 |
150 |
151 | QFrame::NoFrame
152 |
153 |
154 | QFrame::Plain
155 |
156 |
157 |
-
158 |
159 |
160 | Type
161 |
162 |
163 |
-
164 |
165 |
166 | To zero
167 |
168 |
169 |
170 | -
171 |
172 |
173 | Truncate
174 |
175 |
176 |
177 | -
178 |
179 |
180 | Binary
181 |
182 |
183 | true
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 | -
194 |
195 |
196 | 255
197 |
198 |
199 | Qt::Horizontal
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 | QwtPlot
209 | QFrame
210 |
211 |
212 |
213 |
214 |
215 |
216 |
--------------------------------------------------------------------------------